Изображения в Xamarin.Mac

В этой статье рассматривается работа с изображениями и значками в приложении Xamarin.Mac. В нем описывается создание и обслуживание изображений, необходимых для создания значка приложения и использования изображений в коде C# и конструкторе интерфейсов Xcode.

Обзор

При работе с C# и .NET в приложении Xamarin.Mac у вас есть доступ к тем же средствам изображения и значка, в которых работает Objective-C разработчик, и Xcode .

Существует несколько способов использования ресурсов образа в приложении macOS (прежнее название — Mac OS X). От простого отображения изображения в пользовательском интерфейсе приложения, назначая его элементу управления пользовательского интерфейса, например панели инструментов или элементу списка источников, для предоставления значков Xamarin.Mac упрощает добавление большого рисунка в приложения macOS следующими способами:

  • Элементы пользовательского интерфейса — изображения могут отображаться в качестве фона или в составе приложения в представлении изображений (NSImageView).
  • Кнопка — изображения можно отображать в кнопках (NSButton).
  • Ячейка изображения — как часть элемента управления на основе таблицы (NSTableView или NSOutlineView), изображения можно использовать в ячейке изображения (NSImageCell).
  • Элемент панели инструментов — изображения можно добавить на панель инструментов (NSToolbar) как элемент панели инструментов изображения (NSToolbarItem).
  • Значок исходного списка — в составе исходного списка (специально отформатированный NSOutlineView).
  • Значок приложения — ряд изображений можно сгруппировать в .icns набор и использовать в качестве значка приложения. Дополнительные сведения см. в документации по значку приложения.

Кроме того, macOS предоставляет набор предопределенных образов, которые можно использовать во всем приложении.

An example run of the app

В этой статье мы рассмотрим основы работы с изображениями и значками в приложении Xamarin.Mac. Настоятельно рекомендуется сначала ознакомиться со статьей Hello, Mac , в частности в разделах "Введение в Xcode" и "Конструктор интерфейсов" и "Торговых точек" и "Действия ", поскольку рассматриваются основные понятия и методы, которые мы будем использовать в этой статье.

Добавление изображений в проект Xamarin.Mac

При добавлении образа для использования в приложении Xamarin.Mac есть несколько мест и способов, которым разработчик может включить файл образа в источник проекта:

  • Основное дерево проекта [не рекомендуется] — изображения можно добавлять непосредственно в дерево проектов. При вызове изображений, хранящихся в дереве основного проекта из кода, расположение папки не указано. Например: NSImage image = NSImage.ImageNamed("tags.png");.
  • Папка ресурсов [не рекомендуется] — специальная папка ресурсов предназначена для любого файла, который станет частью пакета приложения, такого как значок, экран запуска или общие изображения (или любой другой образ или файл, который разработчик хочет добавить). При вызове образов, хранящихся в папке resources из кода, так же, как и образы, хранящиеся в основном дереве проекта, расположение папки не указано. Например: NSImage.ImageNamed("tags.png").
  • Пользовательская папка или вложенные папки [не рекомендуется] — разработчик может добавить пользовательскую папку в дерево источника проектов и сохранить изображения там. Расположение, в котором добавляется файл, можно вложить в вложенную папку, чтобы помочь упорядочить проект. Например, если разработчик добавил Card папку в проект и вложенную папку Hearts этой папки, сохраните изображение Jack.png в папке, NSImage.ImageNamed("Card/Hearts/Jack.png") загрузит образ во Hearts время выполнения.
  • Наборы образов каталога активов [предпочтительный] — добавлены в OS X El Capitan, наборы образов каталогов активов содержат все версии или представления образа, необходимые для поддержки различных устройств и коэффициентов масштабирования для приложения. Вместо использования имени файла ресурсов образа (@1x, @2x).

Добавление изображений в набор образов каталога активов

Как упоминалось выше, наборы образов каталогов активов содержат все версии или представления образа, необходимые для поддержки различных устройств и коэффициентов масштабирования для приложения. Вместо того чтобы полагаться на имя файла ресурсов изображения (см. раздел "Независимые изображения разрешения" и "Nomenclature выше"), наборы изображений используют редактор ресурсов, чтобы указать, какой образ принадлежит устройству и /или разрешению.

  1. На панели решения дважды щелкните файл Assets.xcassets, чтобы открыть его для редактирования:

    Selecting the Assets.xcassets

  2. Щелкните правой кнопкой мыши список ресурсов и выберите новый набор изображений:

    Adding a new image set

  3. Выберите новый набор изображений и откроется редактор:

    Selecting the new image set

  4. Здесь можно перетащить изображения для каждого из различных устройств и разрешений.

  5. Дважды щелкните имя нового набора изображений в списке ресурсов, чтобы изменить его:

    Editing the image set name

Специальный класс Vector, добавленный в наборы изображений, который позволяет включать форматированный вектор PDF в набор, а не включать отдельные растровые файлы в разных разрешениях. Используя этот метод, вы предоставляете один векторный файл для разрешения @1x (отформатированный как векторНЫЙ PDF-файл), а @2x и @3x версии файла будут создаваться во время компиляции и включаться в пакет приложения.

The image set editor interface

Например, если вы включаете MonkeyIcon.pdf файл в качестве вектора каталога активов с разрешением 150px x 150px, следующие растровые ресурсы будут включены в окончательный пакет приложений при компиляции:

  1. MonkeyIcon@1x.png — разрешение 150 пикселей x 150px.
  2. MonkeyIcon@2x.png — разрешение 300 пикселей x 300px.
  3. MonkeyIcon@3x.png — разрешение 450 пикселей x 450px.

При использовании векторных изображений PDF в каталогах активов следует учитывать следующее:

  • Это не полная поддержка вектора, так как PDF-файл будет растеризирован на растровое изображение во время компиляции и точечные изображения, отправленные в окончательном приложении.
  • Невозможно изменить размер изображения после его установки в каталоге активов. Если вы пытаетесь изменить размер изображения (в коде или с помощью классов автоматического макета и размера), изображение будет искажено так же, как и любое другое растровое изображение.

При использовании набора изображений в построителе интерфейсов Xcode можно просто выбрать имя набора из раскрывающегося списка в инспекторе атрибутов:

Selecting an image set in Xcode's Interface Builder

Добавление новых коллекций ресурсов

При работе с изображениями в каталогах ресурсов может возникнуть время, когда требуется создать новую коллекцию, а не добавлять все изображения в коллекцию Assets.xcassets . Например, при проектировании ресурсов по запросу.

Чтобы добавить новый каталог активов в проект, выполните приведенные далее действия.

  1. Щелкните проект правой кнопкой мыши на панели решения и выберите "Добавить>новый файл" ...

  2. Выберите каталог активов Mac>, введите имя коллекции и нажмите кнопку "Создать".

    Adding a new Asset Catalog

Здесь вы можете работать с коллекцией так же, как и коллекция assets.xcassets по умолчанию, автоматически включенная в проект.

Добавление изображений в ресурсы

Внимание

Этот метод работы с изображениями в приложении macOS не рекомендуется apple. Вместо этого следует использовать наборы образов каталога активов для управления изображениями приложения.

Прежде чем использовать файл изображения в приложении Xamarin.Mac (в коде C# или в построителе интерфейсов), его необходимо включить в папку ресурсов проекта в качестве ресурса пакета. Чтобы добавить файл в проект, сделайте следующее:

  1. Щелкните правой кнопкой мыши папку "Ресурсы " в проекте на панели решения и выберите "Добавить>файлы..."

    Adding a file

  2. В диалоговом окне "Добавить файлы файлов" выберите файлы изображений, которые нужно добавить в проект, выберите BundleResource действие "Переопределить сборку" и нажмите кнопку "Открыть":

    Selecting the files to add

  3. Если файлы еще не находятся в папке ресурсов, вам будет предложено скопировать, переместить или связать файлы. Выберите все ваши потребности, как правило, это будет Копировать:

    Selecting the add action

  4. Новые файлы будут включены в проект и прочитаны для использования:

    The new image files added to the Solution Pad

  5. Повторите процесс для всех необходимых файлов изображений.

В приложении Xamarin.Mac можно использовать любой png, jpg или pdf-файл в качестве исходного изображения. В следующем разделе мы рассмотрим добавление версий изображений и значков с высоким разрешением для поддержки Mac на основе Сетчатки.

Внимание

Если вы добавляете изображения в папку "Ресурсы" , можно оставить действие "Переопределение сборки" значение Default. Действие сборки по умолчанию для этой папки BundleResource.

Предоставление версий с высоким разрешением всех графических ресурсов приложения

Любой графический ресурс, добавляемый в приложение Xamarin.Mac (значки, пользовательские элементы управления, настраиваемые курсоры, пользовательские рисунки и т. д.), должен иметь версии высокого разрешения в дополнение к их версиям стандартного разрешения. Это необходимо, чтобы приложение выглядело лучше всего при запуске на компьютере Mac с дисплеем Retina.

Принятие соглашения об именовании @2x

Внимание

Этот метод работы с изображениями в приложении macOS не рекомендуется apple. Вместо этого следует использовать наборы образов каталога активов для управления изображениями приложения.

При создании стандартных и высокоуровневых версий образа следуйте этому соглашению об именовании пары образов при их включении в проект Xamarin.Mac:

  • Расширение ImageName.filename (пример: tags.png) -
  • Расширение High-Resolution - ImageName@2x.filename (пример: ) tags@2x.png

При добавлении в проект они будут отображаться следующим образом:

The image files in the Solution Pad

Когда изображение назначается элементу пользовательского интерфейса в Конструкторе интерфейсов, вы просто выберете файл в ImageName.Формат расширения filename (пример: tags.png). То же самое для использования изображения в коде C#, вы выберете файл в ImageName.Формат расширения filename.

При запуске приложения Xamarin.Mac на компьютере Mac имя образа.Изображение формата расширения имени файла будет использоваться в стандартных дисплеях разрешения, ImageName@2x.filenameизображение -extension будет автоматически выбрано на базах дисплея Retina Mac.

Использование изображений в построителе интерфейсов

Любой ресурс изображения, добавленный в папку Resources в проекте Xamarin.Mac, и установите действие сборки в BundleResource автоматически отображается в конструкторе интерфейсов и может быть выбран в составе элемента пользовательского интерфейса (если он обрабатывает изображения).

Чтобы использовать образ в построителе интерфейсов, сделайте следующее:

  1. Добавьте изображение в папку "Ресурсы" с действием BundleResource сборки:

    An image resource in the Solution Pad

  2. Дважды щелкните файл Main.storyboard , чтобы открыть его для редактирования в Конструкторе интерфейсов:

    Editing the main storyboard

  3. Перетащите элемент пользовательского интерфейса, который принимает изображения в область конструктора (например, элемент панели инструментов изображения):

    Editing a toolbar item

  4. Выберите изображение, добавленное в папку "Ресурсы " в раскрывающемся списке "Имя образа":

    Selecting an image for a toolbar item

  5. Выбранный образ будет отображаться в области конструктора:

    The image being displayed in the Toolbar editor

  6. Сохраните изменения и вернитесь к Visual Studio для Mac для синхронизации с Xcode.

Приведенные выше действия работают для любого элемента пользовательского интерфейса, который позволяет задать свойство изображения в инспекторе атрибутов. Опять же, если вы включили @2x версию файла изображения, он будет автоматически использоваться в Macs на основе retina Display.

Внимание

Если изображение недоступно в раскрывающемся списке "Имя образа", закройте проект раскадровки в Xcode и снова откройте его из Visual Studio для Mac. Если изображение по-прежнему недоступно, убедитесь, что его действиеBundleResource сборки и что изображение было добавлено в папку Resources .

Использование изображений в коде C#

При загрузке образа в память с помощью кода C# в приложении Xamarin.Mac образ будет храниться в объекте NSImage . Если файл изображения был включен в пакет приложений Xamarin.Mac (включенный в ресурсы), используйте следующий код для загрузки образа:

NSImage image = NSImage.ImageNamed("tags.png");

Приведенный выше код использует статический ImageNamed("...") метод класса для загрузки заданного NSImage изображения в память из папки Resources , если изображение не удается найти, null будет возвращено. Как и изображения, назначенные в построителе интерфейсов, если вы включили @2x версию файла изображения, он будет автоматически использоваться в Mac на основе дисплея Сетчатки.

Чтобы загрузить образы вне пакета приложения (из файловой системы Mac), используйте следующий код:

NSImage image = new NSImage("/Users/KMullins/Documents/photo.jpg")

Работа с образами шаблонов

На основе дизайна приложения macOS может возникнуть время, когда необходимо настроить значок или изображение внутри пользовательского интерфейса, чтобы соответствовать изменению цветовой схемы (например, на основе предпочтений пользователя).

Чтобы добиться этого эффекта, переключите режим отрисовки ресурса изображения на образ шаблона:

Setting a template image

В построителе интерфейсов Xcode назначьте ресурс изображения элементу управления пользовательского интерфейса:

Selecting an image in Xcode's Interface Builder

Или при необходимости задайте источник изображения в коде:

MyIcon.Image = NSImage.ImageNamed ("MessageIcon");

Добавьте следующую общедоступную функцию в контроллер представления:

public NSImage ImageTintedWithColor(NSImage sourceImage, NSColor tintColor)
    => NSImage.ImageWithSize(sourceImage.Size, false, rect => {
        // Draw the original source image
        sourceImage.DrawInRect(rect, CGRect.Empty, NSCompositingOperation.SourceOver, 1f);

        // Apply tint
        tintColor.Set();
        NSGraphics.RectFill(rect, NSCompositingOperation.SourceAtop);

        return true;
    });

Внимание

Особенно с появлением темного режима в macOS Mojave важно избежать LockFocus API при повторной отрисовке NSImage пользовательских объектов. Такие изображения становятся статическими и не будут автоматически обновляться для учета изменений внешнего вида или отображения плотности.

Используя приведенный выше механизм на основе обработчика, повторная отрисовка динамических условий будет происходить автоматически при NSImage размещении, например в объекте NSImageView.

Наконец, чтобы оттенить изображение шаблона, вызовите эту функцию для цвета изображения:

MyIcon.Image = ImageTintedWithColor (MyIcon.Image, NSColor.Red);

Использование изображений с представлениями таблиц

Чтобы включить изображение в ячейку в NSTableViewячейку, необходимо изменить способ возврата данных методом представления NSTableViewDelegate'sGetViewForItem таблицы, чтобы использовать NSTableCellView вместо типичных NSTextField. Например:

public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
{

    // This pattern allows you reuse existing views when they are no-longer in use.
    // If the returned view is null, you instance up a new view
    // If a non-null view is returned, you modify it enough to reflect the new data
    NSTableCellView view = (NSTableCellView)tableView.MakeView (tableColumn.Title, this);
    if (view == null) {
        view = new NSTableCellView ();
        if (tableColumn.Title == "Product") {
            view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
            view.AddSubview (view.ImageView);
            view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
        } else {
            view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
        }
        view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
        view.AddSubview (view.TextField);
        view.Identifier = tableColumn.Title;
        view.TextField.BackgroundColor = NSColor.Clear;
        view.TextField.Bordered = false;
        view.TextField.Selectable = false;
        view.TextField.Editable = true;

        view.TextField.EditingEnded += (sender, e) => {

            // Take action based on type
            switch(view.Identifier) {
            case "Product":
                DataSource.Products [(int)view.TextField.Tag].Title = view.TextField.StringValue;
                break;
            case "Details":
                DataSource.Products [(int)view.TextField.Tag].Description = view.TextField.StringValue;
                break; 
            }
        };
    }

    // Tag view
    view.TextField.Tag = row;

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.ImageView.Image = NSImage.ImageNamed ("tags.png");
        view.TextField.StringValue = DataSource.Products [(int)row].Title;
        break;
    case "Details":
        view.TextField.StringValue = DataSource.Products [(int)row].Description;
        break;
    }

    return view;
}

Здесь есть несколько линий интереса. Во-первых, для столбцов, которые мы хотим включить изображение, мы создадим новый NSImageView требуемый размер и расположение, мы также создадим новое NSTextField и поместим его положение по умолчанию на основе того, используется ли изображение:

if (tableColumn.Title == "Product") {
    view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
    view.AddSubview (view.ImageView);
    view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
} else {
    view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
}

Во-вторых, необходимо включить новое представление изображения и текстовое поле в родительский NSTableCellViewэлемент:

view.AddSubview (view.ImageView);
...

view.AddSubview (view.TextField);
...

Наконец, необходимо сообщить текстовому полю, что он может сжиматься и расти с помощью ячейки представления таблицы:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Пример результата:

An example of displaying an image in an app

Дополнительные сведения о работе с представлениями таблиц см. в документации по представлениям таблиц.

Использование изображений с представлениями структуры

Чтобы включить изображение в ячейку в NSOutlineViewячейку, необходимо изменить способ возврата данных методом "Представление структуры NSTableViewDelegate'sGetView " вместо NSTableCellView типичного NSTextField. Например:

public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) {
    // Cast item
    var product = item as Product;

    // This pattern allows you reuse existing views when they are no-longer in use.
    // If the returned view is null, you instance up a new view
    // If a non-null view is returned, you modify it enough to reflect the new data
    NSTableCellView view = (NSTableCellView)outlineView.MakeView (tableColumn.Title, this);
    if (view == null) {
        view = new NSTableCellView ();
        if (tableColumn.Title == "Product") {
            view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
            view.AddSubview (view.ImageView);
            view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
        } else {
            view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
        }
        view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;
        view.AddSubview (view.TextField);
        view.Identifier = tableColumn.Title;
        view.TextField.BackgroundColor = NSColor.Clear;
        view.TextField.Bordered = false;
        view.TextField.Selectable = false;
        view.TextField.Editable = !product.IsProductGroup;
    }

    // Tag view
    view.TextField.Tag = outlineView.RowForItem (item);

    // Allow for edit
    view.TextField.EditingEnded += (sender, e) => {

        // Grab product
        var prod = outlineView.ItemAtRow(view.Tag) as Product;

        // Take action based on type
        switch(view.Identifier) {
        case "Product":
            prod.Title = view.TextField.StringValue;
            break;
        case "Details":
            prod.Description = view.TextField.StringValue;
            break; 
        }
    };

    // Setup view based on the column selected
    switch (tableColumn.Title) {
    case "Product":
        view.ImageView.Image = NSImage.ImageNamed (product.IsProductGroup ? "tags.png" : "tag.png");
        view.TextField.StringValue = product.Title;
        break;
    case "Details":
        view.TextField.StringValue = product.Description;
        break;
    }

    return view;
}

Здесь есть несколько линий интереса. Во-первых, для столбцов, которые мы хотим включить изображение, мы создадим новый NSImageView требуемый размер и расположение, мы также создадим новое NSTextField и поместим его положение по умолчанию на основе того, используется ли изображение:

if (tableColumn.Title == "Product") {
    view.ImageView = new NSImageView (new CGRect (0, 0, 16, 16));
    view.AddSubview (view.ImageView);
    view.TextField = new NSTextField (new CGRect (20, 0, 400, 16));
} else {
    view.TextField = new NSTextField (new CGRect (0, 0, 400, 16));
}

Во-вторых, необходимо включить новое представление изображения и текстовое поле в родительский NSTableCellViewэлемент:

view.AddSubview (view.ImageView);
...

view.AddSubview (view.TextField);
...

Наконец, необходимо сообщить текстовому полю, что он может сжиматься и расти с помощью ячейки представления таблицы:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Пример результата:

An example of an image being displayed in an Outline View

Дополнительные сведения о работе с представлениями структуры см. в документации по представлениям структуры.

Итоги

В этой статье подробно рассматривается работа с изображениями и значками в приложении Xamarin.Mac. Мы видели различные типы и использование изображений, как использовать изображения и значки в построителе интерфейсов Xcode и как работать с изображениями и значками в коде C#.