Imagens em Xamarin.Mac

Este artigo aborda o trabalho com imagens e ícones em um aplicativo Xamarin.Mac. Ele descreve a criação e a manutenção das imagens necessárias para criar o ícone do aplicativo e o uso de imagens no código C# e no Construtor de Interfaces do Xcode.

Visão geral

Ao trabalhar com C# e .NET em um aplicativo Xamarin.Mac, você tem acesso às mesmas ferramentas de imagem e ícone que um desenvolvedor trabalhando e Objective-Co Xcode faz.

Há várias maneiras pelas quais os ativos de imagem são usados dentro de um aplicativo macOS (anteriormente conhecido como Mac OS X). Desde simplesmente exibir uma imagem como parte da interface do usuário do seu aplicativo, atribuí-la a um controle de interface do usuário, como uma barra de ferramentas ou um item de lista de código-fonte, até fornecer ícones, o Xamarin.Mac facilita a adição de um ótimo trabalho artístico aos seus aplicativos macOS das seguintes maneiras:

  • Elementos da interface do usuário - As imagens podem ser exibidas como planos de fundo ou como parte do aplicativo em um Modo de Exibição de Imagem (NSImageView).
  • Botão - As imagens podem ser exibidas em botões (NSButton).
  • Célula de Imagem - Como parte de um controle baseado em tabela (NSTableView ou NSOutlineView), as imagens podem ser usadas em uma Célula de Imagem (NSImageCell).
  • Item da barra de ferramentas - As imagens podem ser adicionadas a uma barra de ferramentas (NSToolbar) como um item da barra de ferramentas de imagem (NSToolbarItem).
  • Ícone da Lista de Fontes - Como parte de uma Lista de Fontes (uma lista especialmente formatada NSOutlineView).
  • Ícone do aplicativo - Uma série de imagens pode ser agrupada em um .icns conjunto e usada como ícone do seu aplicativo. Consulte nossa documentação do ícone do aplicativo para obter mais informações.

Além disso, o macOS fornece um conjunto de imagens predefinidas que podem ser usadas em todo o aplicativo.

An example run of the app

Neste artigo, abordaremos os conceitos básicos de como trabalhar com imagens e ícones em um aplicativo Xamarin.Mac. É altamente recomendável que você trabalhe primeiro no artigo Olá, Mac, especificamente nas seções Introdução ao Xcode e ao Construtor de Interface e Saídas e Ações, pois ele aborda os principais conceitos e técnicas que usaremos neste artigo.

Adicionando imagens a um projeto Xamarin.Mac

Ao adicionar uma imagem para uso em um aplicativo Xamarin.Mac, há vários lugares e maneiras que o desenvolvedor pode incluir o arquivo de imagem na origem do projeto:

  • Árvore de projeto principal [preterida] - As imagens podem ser adicionadas diretamente à árvore de projetos. Ao chamar imagens armazenadas na árvore principal do projeto a partir do código, nenhum local de pasta é especificado. Por exemplo: NSImage image = NSImage.ImageNamed("tags.png");.
  • Pasta Recursos [preterida] - A pasta Recursos especiais é para qualquer arquivo que se tornará parte do Pacote do Aplicativo, como Ícone, Tela de Inicialização ou Imagens gerais (ou qualquer outra imagem ou arquivo que o desenvolvedor deseje adicionar). Ao chamar imagens armazenadas na pasta Recursos a partir do código, assim como as imagens armazenadas na árvore principal do projeto, nenhum local de pasta é especificado. Por exemplo: NSImage.ImageNamed("tags.png").
  • Pasta ou subpasta personalizada [preterida] - O desenvolvedor pode adicionar uma pasta personalizada à árvore de código-fonte do projeto e armazenar as imagens lá. O local onde o arquivo é adicionado pode ser aninhado em uma subpasta para ajudar ainda mais a organizar o projeto. Por exemplo, se o desenvolvedor adicionou uma Card pasta ao projeto e uma subpasta de Hearts a essa pasta, em seguida, armazenar uma imagem Jack.png na Hearts pasta, NSImage.ImageNamed("Card/Hearts/Jack.png") carregaria a imagem em tempo de execução.
  • Conjuntos de Imagens do Catálogo de Ativos [preferencial] - Adicionados ao OS X El Capitan, os Conjuntos de Imagens de Catálogos de Ativos contêm todas as versões ou representações de uma imagem que são necessárias para suportar vários dispositivos e fatores de escala para o seu aplicativo. Em vez de confiar no nome do arquivo de ativos de imagem (@1x, @2x).

Adicionando imagens a um conjunto de imagens do catálogo de ativos

Como dito acima, um conjunto de imagens de catálogos de ativos contém todas as versões ou representações de uma imagem que são necessárias para oferecer suporte a vários dispositivos e fatores de escala para seu aplicativo. Em vez de confiar no nome do arquivo de ativos de imagem (consulte a Nomenclatura de Imagens Independentes de Resolução acima), os Conjuntos de Imagens usam o Editor de Ativos para especificar qual imagem pertence a qual dispositivo e/ou resolução.

  1. No Solution Pad, clique duas vezes no arquivo Assets.xcassets para abri-lo para edição:

    Selecting the Assets.xcassets

  2. Clique com o botão direito do mouse na Lista de Ativos e selecione Novo Conjunto de Imagens:

    Adding a new image set

  3. Selecione o novo conjunto de imagens e o editor será exibido:

    Selecting the new image set

  4. A partir daqui, podemos arrastar imagens para cada um dos diferentes dispositivos e resoluções necessárias.

  5. Clique duas vezes no Nome do novo conjunto de imagens na Lista de Ativos para editá-lo:

    Editing the image set name

Uma classe Vector especial como foi adicionada aos conjuntos de imagens que nos permite incluir uma imagem vetorial formatada em PDF no conjunto de imagens, em vez de incluir arquivos bitmap individuais nas diferentes resoluções. Usando esse método, você fornece um único arquivo vetorial para a resolução @1x (formatado como um arquivo PDF vetorial) e as versões @2x e @3x do arquivo serão geradas em tempo de compilação e incluídas no pacote do aplicativo.

The image set editor interface

Por exemplo, se você incluir um MonkeyIcon.pdf arquivo como vetor de um Catálogo de Ativos com resolução de 150px x 150px, os seguintes ativos de bitmap serão incluídos no pacote final do aplicativo quando ele for compilado:

  1. MonkeyIcon@1x.png - Resolução de 150px x 150px.
  2. MonkeyIcon@2x.png - Resolução de 300px x 300px.
  3. MonkeyIcon@3x.png - Resolução de 450px x 450px.

O seguinte deve ser levado em consideração ao usar imagens vetoriais PDF em catálogos de ativos:

  • Isso não é suporte vetorial completo, pois o PDF será rasterizado para um bitmap em tempo de compilação e os bitmaps enviados no aplicativo final.
  • Não é possível ajustar o tamanho da imagem depois que ela for definida no Catálogo de Ativos. Se você tentar redimensionar a imagem (em código ou usando Auto Layout e Classes de Tamanho), a imagem será distorcida como qualquer outro bitmap.

Ao usar um Conjunto de Imagens no Construtor de Interfaces do Xcode, você pode simplesmente selecionar o nome do conjunto na lista suspensa no Inspetor de Atributos:

Selecting an image set in Xcode's Interface Builder

Adicionando novas coleções de ativos

Ao trabalhar com imagens em Catálogos de Ativos, pode haver momentos em que você deseja criar uma nova coleção, em vez de adicionar todas as imagens à coleção Assets.xcassets . Por exemplo, ao projetar recursos sob demanda.

Para adicionar um novo Catálogo de Ativos ao seu projeto:

  1. Clique com o botão direito do mouse no projeto no Solution Pad e selecione Add>New File...

  2. Selecione Catálogo de Ativos do Mac>, insira um Nome para a coleção e clique no botão Novo:

    Adding a new Asset Catalog

A partir daqui, você pode trabalhar com a coleção da mesma forma que a coleção Assets.xcassets padrão incluída automaticamente no projeto.

Adicionando imagens a recursos

Importante

Esse método de trabalhar com imagens em um aplicativo macOS foi preterido pela Apple. Você deve usar os Conjuntos de Imagens do Catálogo de Ativos para gerenciar as imagens do seu aplicativo.

Antes de usar um arquivo de imagem em seu aplicativo Xamarin.Mac (em código C# ou no Construtor de Interfaces), ele precisa ser incluído na pasta Recursos do projeto como um recurso de pacote. Para adicionar um arquivo a um projeto, faça o seguinte:

  1. Clique com o botão direito do mouse na pasta Recursos em seu projeto no Solution Pad e selecione Add>Add Files...:

    Adding a file

  2. Na caixa de diálogo Adicionar arquivos, selecione os arquivos de imagens a serem adicionados ao projeto, selecione BundleResource a ação Substituir compilação e clique no botão Abrir:

    Selecting the files to add

  3. Se os arquivos ainda não estiverem na pasta Recursos, você será perguntado se deseja Copiar, Mover ou Vincular os arquivos. Escolha qual se adapta às suas necessidades, normalmente isso será Copiar:

    Selecting the add action

  4. Os novos arquivos serão incluídos no projeto e lidos para uso:

    The new image files added to the Solution Pad

  5. Repita o processo para todos os arquivos de imagem necessários.

Você pode usar qualquer arquivo png, jpg ou pdf como imagem de origem em seu aplicativo Xamarin.Mac. Na próxima seção, veremos como adicionar versões de alta resolução de nossas imagens e ícones para oferecer suporte a Macs baseados em Retina.

Importante

Se você estiver adicionando Imagens à pasta Recursos , poderá deixar a ação Substituir compilação definida como Padrão. A Ação de Criação padrão para esta pasta é BundleResource.

Fornecer versões de alta resolução de todos os recursos gráficos do aplicativo

Qualquer ativo gráfico adicionado a um aplicativo Xamarin.Mac (ícones, controles personalizados, cursores personalizados, arte personalizada, etc.) precisa ter versões de alta resolução, além de suas versões de resolução padrão. Isso é necessário para que seu aplicativo tenha a melhor aparência quando executado em um computador Mac equipado com Retina Display.

Adotar a convenção de nomenclatura @2x

Importante

Esse método de trabalhar com imagens em um aplicativo macOS foi preterido pela Apple. Você deve usar os Conjuntos de Imagens do Catálogo de Ativos para gerenciar as imagens do seu aplicativo.

Ao criar as versões padrão e de alta resolução de uma imagem, siga esta convenção de nomenclatura para o par de imagens ao incluí-las em seu projeto Xamarin.Mac:

  • ImageName.filename-extension de resolução - padrão (exemplo: tags.png)
  • Extensão de alta resolução - ImageName@2x.filename (exemplo: ) tags@2x.png

Quando adicionados a um projeto, eles apareceriam da seguinte maneira:

The image files in the Solution Pad

Quando uma imagem é atribuída a um elemento da interface do usuário no Construtor de Interfaces, você simplesmente escolhe o arquivo no ImageName.formato de extensão de nome de arquivo (Exemplo: tags.png). O mesmo para usar uma imagem no código C#, você escolherá o arquivo no ImageName.formato de extensão de nome de arquivo.

Quando o aplicativo Xamarin.Mac é executado em um Mac, o ImageName.A imagem de formato de extensão de nome de arquivo será usada em monitores de resolução padrão, a ImageName@2x.filenameimagem de extensão será automaticamente escolhida em Macs de bases Retina Display.

Usando imagens no Construtor de Interfaces

Qualquer recurso de imagem que você adicionou à pasta Recursos em seu projeto Xamarin.Mac e definiu a ação de compilação como BundleResource aparecerá automaticamente no Construtor de Interface e poderá ser selecionado como parte de um elemento da interface do usuário (se ele manipular imagens).

Para usar uma imagem no construtor de interfaces, faça o seguinte:

  1. Adicione uma imagem à pasta Recursos com uma Ação de Criação de BundleResource:

    An image resource in the Solution Pad

  2. Clique duas vezes no arquivo Main.storyboard para abri-lo para edição no Construtor de Interfaces:

    Editing the main storyboard

  3. Arraste um elemento da interface do usuário que leva imagens para a superfície de design (por exemplo, um Item da Barra de Ferramentas de Imagem):

    Editing a toolbar item

  4. Selecione a imagem que você adicionou à pasta Recursos na lista suspensa Nome da imagem:

    Selecting an image for a toolbar item

  5. A imagem selecionada será exibida na superfície de design:

    The image being displayed in the Toolbar editor

  6. Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.

As etapas acima funcionam para qualquer elemento da interface do usuário que permita que sua propriedade image seja definida no Inspetor de Atributos. Novamente, se você tiver incluído uma versão @2x do seu arquivo de imagem, ele será usado automaticamente em Macs baseados no Retina Display.

Importante

Se a Imagem não estiver disponível na lista suspensa Nome da Imagem, feche seu projeto .storyboard no Xcode e abra-o novamente no Visual Studio para Mac. Se a imagem ainda não estiver disponível, verifique se a Ação de Criação está BundleResource e se a imagem foi adicionada à pasta Recursos .

Usando imagens em código C#

Ao carregar uma imagem na memória usando o código C# em seu aplicativo Xamarin.Mac, a imagem será armazenada em um NSImage objeto. Se o arquivo de imagem tiver sido incluído no pacote de aplicativos Xamarin.Mac (incluído nos recursos), use o seguinte código para carregar a imagem:

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

O código acima usa o método estático ImageNamed("...") da classe para carregar a imagem fornecida na memória da pasta Recursos, se a imagem não puder ser encontrada, null será retornada.NSImage Como as imagens atribuídas no Construtor de Interfaces, se você tiver incluído uma versão @2x do arquivo de imagem, ela será usada automaticamente em Macs baseados no Retina Display.

Para carregar imagens fora do pacote do aplicativo (do sistema de arquivos Mac), use o seguinte código:

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

Trabalhando com imagens de modelo

Com base no design do seu aplicativo macOS, pode haver momentos em que você precise personalizar um ícone ou imagem dentro da Interface do Usuário para corresponder a uma alteração no esquema de cores (por exemplo, com base nas preferências do usuário).

Para obter esse efeito, alterne o Modo de renderização do ativo de imagem para Imagem de modelo:

Setting a template image

No Construtor de Interfaces do Xcode, atribua o Ativo de Imagem a um controle de interface do usuário:

Selecting an image in Xcode's Interface Builder

Ou, opcionalmente, defina o código-fonte da imagem no código:

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

Adicione a seguinte função pública ao seu controlador de exibição:

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;
    });

Importante

Particularmente com o advento do Modo Escuro no macOS Mojave, é importante evitar a LockFocus API ao recriar objetos renderizados NSImage de forma personalizada. Essas imagens tornam-se estáticas e não serão atualizadas automaticamente para levar em conta as alterações de aparência ou densidade de exibição.

Ao empregar o mecanismo baseado em manipulador acima, a rerenderização para condições dinâmicas acontecerá automaticamente quando o NSImage estiver hospedado, por exemplo, em um NSImageViewarquivo .

Finalmente, para colorir uma imagem de modelo, chame esta função contra a imagem para colorir:

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

Usando imagens com modos de exibição de tabela

Para incluir uma imagem como parte da célula em um NSTableView, você precisará alterar como os dados são retornados pelo método doGetViewForItemNSTableViewDelegate'sModo de Exibição de Tabela para usar um NSTableCellView em vez do típico NSTextField. Por exemplo:

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;
}

Há algumas linhas de interesse aqui. Primeiro, para colunas que queremos incluir uma imagem, criamos uma nova NSImageView do tamanho e localização necessários, também criamos uma nova NSTextField e colocamos sua posição padrão com base em se estamos ou não usando uma imagem:

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));
}

Em segundo lugar, precisamos incluir o novo Modo de Exibição de Imagem e Campo de Texto no pai NSTableCellView:

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

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

Por fim, precisamos dizer ao Campo de Texto que ele pode diminuir e crescer com a Célula de Exibição de Tabela:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Exemplo de saída:

An example of displaying an image in an app

Para obter mais informações sobre como trabalhar com Exibições de Tabela, consulte nossa documentação de Exibições de Tabela .

Usando imagens com modos de exibição de estrutura de tópicos

Para incluir uma imagem como parte da célula em um NSOutlineView, você precisará alterar como os dados são retornados pelo método doGetViewNSTableViewDelegate'sModo de Exibição de Estrutura de Tópicos para usar um NSTableCellView em vez do típico NSTextField. Por exemplo:

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;
}

Há algumas linhas de interesse aqui. Primeiro, para colunas que queremos incluir uma imagem, criamos uma nova NSImageView do tamanho e localização necessários, também criamos uma nova NSTextField e colocamos sua posição padrão com base em se estamos ou não usando uma imagem:

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));
}

Em segundo lugar, precisamos incluir o novo Modo de Exibição de Imagem e Campo de Texto no pai NSTableCellView:

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

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

Por fim, precisamos dizer ao Campo de Texto que ele pode diminuir e crescer com a Célula de Exibição de Tabela:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Exemplo de saída:

An example of an image being displayed in an Outline View

Para obter mais informações sobre como trabalhar com Modos de Exibição de Estrutura de Tópicos, consulte nossa documentação de Modos de Exibição de Estrutura de Tópicos .

Resumo

Este artigo deu uma olhada detalhada no trabalho com imagens e ícones em um aplicativo Xamarin.Mac. Vimos os diferentes tipos e usos de Imagens, como usar Imagens e Ícones no Construtor de Interfaces do Xcode e como trabalhar com Imagens e Ícones em código C#.