Compartilhar via


Imagens no 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 que trabalha e Objective-C o Xcode tem.

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 aplicativo até atribuí-la a um controle de interface do usuário, como uma barra de ferramentas ou um item de lista de origem, até fornecer ícones, o Xamarin.Mac facilita a adição de ótimas ilustrações aos aplicativos macOS das seguintes maneiras:

  • Elementos da interface do usuário - As imagens podem ser exibidas como planos de fundo ou como parte do seu 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 (um formato especial NSOutlineView).
  • Ícone do aplicativo - Uma série de imagens pode ser agrupada em um .icns conjunto e usada como ícone do 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.

Um exemplo de execução do aplicativo

Neste artigo, abordaremos as noções básicas 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 Interfaces 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 locais e maneiras pelas quais o desenvolvedor pode incluir o arquivo de imagem na origem do projeto:

  • Árvore principal do projeto [obsoleto] - As imagens podem ser adicionadas diretamente à árvore de projetos. Ao chamar imagens armazenadas na árvore de projeto principal do código, nenhum local de pasta é especificado. Por exemplo: NSImage image = NSImage.ImageNamed("tags.png");.
  • Pasta de recursos [obsoleto] - A pasta especial de recursos é 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 Resources 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 [obsoleta] - O desenvolvedor pode adicionar uma pasta personalizada à árvore de origem 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 a Hearts essa pasta, armazene uma imagem Jack.png na Hearts pasta, NSImage.ImageNamed("Card/Hearts/Jack.png") carregará 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 do catálogo de ativos contêm todas as versões ou representações de uma imagem necessárias para oferecer suporte a vários dispositivos e fatores de escala para seu aplicativo. Em vez de depender do nome do arquivo de ativos de imagem (@1x, @2x).

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

Conforme mencionado acima, um Asset Catalogs Image Sets 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 depender do nome do arquivo de ativos de imagem (consulte Imagens independentes de resolução e nomenclatura de imagem acima), os Conjuntos de imagens usam o Editor de ativos para especificar qual imagem pertence a qual dispositivo e/ou resolução.

  1. No Painel de Soluções, clique duas vezes no arquivo Assets.xcassets para abri-lo para edição:

    Selecionando o Assets.xcassets

  2. Clique com o botão direito do mouse na Lista de ativos e selecione Novo conjunto de imagens:

    Adicionando um novo conjunto de imagens

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

    Selecionando o novo conjunto de imagens

  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:

    Editando o nome do conjunto de imagens

Uma classe Vector especial foi adicionada aos Conjuntos de imagens que nos permite incluir uma imagem vetorial formatada em PDF no casset, 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 configurável do aplicativo.

A interface do editor de conjunto de imagens

Por exemplo, se você incluir um MonkeyIcon.pdf arquivo como o vetor de um Catálogo de Ativos com uma 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 total a vetores, pois o PDF será rasterizado para um bitmap em tempo de compilação e os bitmaps enviados no aplicativo final.
  • Você não pode ajustar o tamanho da imagem depois que ela tiver sido definida no Catálogo de ativos. Se você tentar redimensionar a imagem (no código ou usando Layout Automático e Classes de Tamanho), a imagem ficará 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:

Selecionando um conjunto de imagens no Construtor de Interfaces do Xcode

Adição de 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 suas 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 Painel de Soluções e selecione Adicionar>Novo Arquivo...

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

    Adicionando um novo Catálogo de Ativos

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 aos recursos

Importante

Esse método de trabalhar com imagens em um aplicativo macOS foi preterido pela Apple. Em vez disso, você deve usar os Conjuntos de Imagens do Catálogo de Recursos para gerenciar as imagens do seu aplicativo.

Antes de usar um arquivo de imagem em seu aplicativo Xamarin.Mac (no 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 Painel de Soluções e selecione Adicionar>Adicionar Arquivos...:

    Como adicionar um arquivo

  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 :

    Selecionando os arquivos a serem adicionados

  3. Se os arquivos ainda não estiverem na pasta Recursos , você será perguntado se deseja copiar, mover ou vincular os arquivos. Escolha qual atende às suas necessidades, normalmente será Copiar:

    Selecionando a ação de adição

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

    Os novos arquivos de imagem adicionados ao Painel de Soluções

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

Você pode usar qualquer arquivo png, jpg ou pdf como uma 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 build definida como Padrão. A Ação de Construção padrão para esta pasta é BundleResource.

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

Qualquer ativo gráfico que você adicionar 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 tela Retina.

Adotar a convenção de nomenclatura @2x

Importante

Esse método de trabalhar com imagens em um aplicativo macOS foi preterido pela Apple. Em vez disso, você deve usar os Conjuntos de Imagens do Catálogo de Recursos 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:

Os arquivos de imagem no Painel de Soluções

Quando uma imagem é atribuída a um elemento de interface do usuário no Construtor de Interfaces, você simplesmente escolhe o arquivo no ImageName.filename-extension (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 do 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á escolhida automaticamente em Macs com base em tela Retina.

Usando imagens no Construtor de Interfaces

Qualquer recurso de imagem que você adicionou à pasta Resources em seu projeto Xamarin.Mac e definiu a ação de build como BundleResource aparecerá automaticamente no Construtor de Interfaces e poderá ser selecionado como parte de um elemento de 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 Resources com uma ação de build de BundleResource:

    Um recurso de imagem no Painel de Soluções

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

    Editando o storyboard principal

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

    Editando um item da barra de ferramentas

  4. Selecione a imagem que você adicionou à pasta Recursos no menu suspenso Nome da imagem:

    Selecionando uma imagem para um item da barra de ferramentas

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

    A imagem que está sendo exibida no editor da barra de ferramentas

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

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

Importante

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

Usando imagens no 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 Resources, se a imagem não puder ser encontrada, null será retornadaNSImage. Assim como as imagens atribuídas no Construtor de Interfaces, se você incluiu uma versão @2x do seu arquivo de imagem, ele será usado automaticamente em Macs baseados em 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 seu Ativo de imagem para Imagem de modelo:

Configurando uma imagem de modelo

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

Selecionando uma imagem no Construtor de Interfaces do Xcode

Ou, opcionalmente, defina a origem 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 reativar 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 nova renderização para condições dinâmicas ocorrerá automaticamente quando o NSImage for hospedado, por exemplo, em um NSImageView.

Por fim, para tingir uma imagem de modelo, chame esta função na imagem para colorir:

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

Usando imagens com exibições de tabela

Para incluir uma imagem como parte da célula em um NSTableView, você precisará alterar a forma como os dados são retornados NSTableViewDelegate's GetViewForItem pelo método da Exibição de tabela para usar um NSTableCellView em vez do .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;
}

Existem algumas linhas de interesse aqui. Primeiro, para colunas que queremos incluir uma imagem, criamos uma nova NSImageView com o tamanho e local necessários, também criamos uma nova NSTextField e colocamos sua posição padrão com base no fato de estarmos 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 a nova visualizaçã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:

Um exemplo de exibição de uma imagem em um aplicativo

Para obter mais informações sobre como trabalhar com Modos de Exibição de Tabela, consulte nossa documentação de Modos de Exibição 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 do GetView NSTableViewDelegate's Modo de Exibição de Estrutura de Tópicos para usar um NSTableCellView em vez do .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;
}

Existem algumas linhas de interesse aqui. Primeiro, para colunas que queremos incluir uma imagem, criamos uma nova NSImageView com o tamanho e local necessários, também criamos uma nova NSTextField e colocamos sua posição padrão com base no fato de estarmos 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 a nova visualizaçã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:

Um exemplo de uma imagem sendo exibida em um Modo de Exibição de Estrutura de Tópicos

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

Resumo

Este artigo examinou detalhadamente como trabalhar 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 no código C#.