Imágenes en Xamarin.Mac

En este artículo se explica cómo trabajar con imágenes e iconos en una aplicación de Xamarin.Mac. Describe cómo crear y mantener las imágenes necesarias para crear el icono de la aplicación y usar imágenes en código de C# y el Generador de interfaces de Xcode.

Información general

Al trabajar con C# y .NET en una aplicación de Xamarin.Mac, tiene acceso a las mismas herramientas de imagen e icono que un desarrollador que trabaja en Objective-C y Xcode .

Hay varias maneras de usar recursos de imagen dentro de una aplicación macOS (anteriormente conocida como Mac OS X). Desde simplemente mostrar una imagen como parte de la interfaz de usuario de la aplicación para, asignarla a un control de interfaz de usuario, como una barra de herramientas o un elemento de lista de origen, proporcionar iconos, Xamarin.Mac facilita la adición de excelentes ilustraciones a las aplicaciones macOS de las maneras siguientes:

  • Elementos de la interfaz de usuario: las imágenes se pueden mostrar como fondos o como parte de la aplicación en una vista de imagen (NSImageView).
  • Botón : las imágenes se pueden mostrar en botones (NSButton).
  • Celda image: como parte de un control basado en tabla (NSTableView o NSOutlineView), las imágenes se pueden usar en una celda image (NSImageCell).
  • Elemento de la barra de herramientas: las imágenes se pueden agregar a una barra de herramientas (NSToolbar) como elemento de la barra de herramientas de imagen (NSToolbarItem).
  • Icono de lista de origen: como parte de una lista de origen NSOutlineView(un formato especial ).
  • Icono de aplicación: se puede agrupar una serie de imágenes en un .icns conjunto y usarse como icono de la aplicación. Consulte nuestra documentación sobre el icono de aplicación para obtener más información.

Además, macOS proporciona un conjunto de imágenes predefinidas que se pueden usar en toda la aplicación.

An example run of the app

En este artículo, trataremos los conceptos básicos de trabajar con imágenes e iconos en una aplicación de Xamarin.Mac. Se recomienda encarecidamente trabajar primero en el artículo Hello, Mac , específicamente en las secciones Introducción a Xcode y Generador de interfaces y Salidas y Acciones , ya que trata conceptos clave y técnicas que usaremos en este artículo.

Adición de imágenes a un proyecto de Xamarin.Mac

Al agregar una imagen para su uso en una aplicación de Xamarin.Mac, hay varios lugares y formas de incluir el archivo de imagen en el origen del proyecto:

  • Árbol de proyecto principal [en desuso] : las imágenes se pueden agregar directamente al árbol de proyectos. Al llamar a imágenes almacenadas en el árbol de proyecto principal desde el código, no se especifica ninguna ubicación de carpeta. Por ejemplo: NSImage image = NSImage.ImageNamed("tags.png");.
  • Carpeta resources [en desuso] : la carpeta especial Resources es para cualquier archivo que se convierta en parte del paquete de la aplicación, como Icon, Launch Screen o general Images (o cualquier otra imagen o archivo que el desarrollador desee agregar). Al llamar a imágenes almacenadas en la carpeta Resources desde el código, al igual que las imágenes almacenadas en el árbol de proyecto principal, no se especifica ninguna ubicación de carpeta. Por ejemplo: NSImage.ImageNamed("tags.png").
  • Carpeta personalizada o subcarpeta [en desuso] : el desarrollador puede agregar una carpeta personalizada al árbol de origen de los proyectos y almacenar las imágenes allí. La ubicación donde se agrega el archivo se puede anidar en una subcarpeta para ayudar a organizar aún más el proyecto. Por ejemplo, si el desarrollador agregó una Card carpeta al proyecto y una subcarpeta de Hearts a esa carpeta, almacenaría una imagen Jack.png en la Hearts carpeta, NSImage.ImageNamed("Card/Hearts/Jack.png") cargaría la imagen en tiempo de ejecución.
  • Conjuntos de imágenes de catálogo de activos [preferido] : agregados en OS X El Capitan, los conjuntos de imágenes de catálogos de activos contienen todas las versiones o representaciones de una imagen que son necesarias para admitir varios dispositivos y factores de escala para la aplicación. En lugar de confiar en el nombre de archivo de los recursos de imagen (@1x, @2x).

Adición de imágenes a un conjunto de imágenes de catálogo de recursos

Como se indicó anteriormente, los conjuntos de imágenes de catálogos de activos contienen todas las versiones o representaciones de una imagen que son necesarias para admitir varios dispositivos y factores de escala para la aplicación. En lugar de confiar en el nombre de archivo de los recursos de imagen (consulte la resolución imágenes independientes y la nomenclatura de imágenes anterior), los conjuntos de imágenes usan el Editor de recursos para especificar qué imagen pertenece a qué dispositivo o resolución.

  1. En el Panel de solución, haga doble clic en el archivo Assets.xcassets para abrirlo para editarlo:

    Selecting the Assets.xcassets

  2. Haga clic con el botón derecho en la lista activos y seleccione Nuevo conjunto de imágenes:

    Adding a new image set

  3. Seleccione el nuevo conjunto de imágenes y se mostrará el editor:

    Selecting the new image set

  4. Desde aquí podemos arrastrar imágenes para cada uno de los diferentes dispositivos y resoluciones necesarios.

  5. Haga doble clic en el nombre del nuevo conjunto de imágenes en la lista de activos para editarlo:

    Editing the image set name

Una clase vector especial tal como se ha agregado a los conjuntos de imágenes que nos permite incluir una imagen vectorial con formato PDF en el conjunto de mayúsculas y minúsculas, incluidos los archivos de mapa de bits individuales en las distintas resoluciones. Con este método, se proporciona un único archivo vectorial para la resolución de @1x (con formato de archivo PDF vectorial) y las versiones de @2x y @3x del archivo se generarán en tiempo de compilación y se incluirán en el lote de la aplicación.

The image set editor interface

Por ejemplo, si incluye un MonkeyIcon.pdf archivo como vector de un catálogo de activos con una resolución de 150px x 150px, los siguientes recursos de mapa de bits se incluirían en el paquete de aplicaciones final cuando se compiló:

  1. MonkeyIcon@1x.png - Resolución de 150px x 150px.
  2. MonkeyIcon@2x.png - Resolución 300px x 300px.
  3. MonkeyIcon@3x.png - Resolución de 450px x 450px.

Debe tenerse en cuenta lo siguiente al usar imágenes vectoriales PDF en catálogos de activos:

  • Esto no es compatibilidad con vectores completos, ya que el PDF se rasterizará en un mapa de bits en tiempo de compilación y los mapas de bits enviados en la aplicación final.
  • No se puede ajustar el tamaño de la imagen una vez establecida en el catálogo de activos. Si intenta cambiar el tamaño de la imagen (ya sea en código o mediante el diseño automático y las clases de tamaño), la imagen se distorsionará igual que cualquier otro mapa de bits.

Al usar un conjunto de imágenes en el Generador de interfaces de Xcode, simplemente puede seleccionar el nombre del conjunto en la lista desplegable del Inspector de atributos:

Selecting an image set in Xcode's Interface Builder

Adición de nuevas colecciones de recursos

Al trabajar con imágenes en catálogos de activos, puede haber ocasiones en las que quiera crear una nueva colección, en lugar de agregar todas las imágenes a la colección Assets.xcassets . Por ejemplo, al diseñar recursos a petición.

Para agregar un nuevo catálogo de activos al proyecto:

  1. Haga clic con el botón derecho en el proyecto en el Panel de solución y seleccione Agregar>nuevo archivo...

  2. Seleccione Catálogo de activos de Mac>, escriba un nombre para la colección y haga clic en el botón Nuevo:

    Adding a new Asset Catalog

Desde aquí puede trabajar con la colección de la misma manera que la colección Assets.xcassets predeterminada que se incluye automáticamente en el proyecto.

Adición de imágenes a recursos

Importante

Apple ha dejado de usar este método para trabajar con imágenes en una aplicación macOS. En su lugar, debes usar Asset Catalog Image Sets para administrar las imágenes de la aplicación.

Para poder usar un archivo de imagen en la aplicación de Xamarin.Mac (ya sea en código de C# o desde interface Builder), debe incluirse en la carpeta Resources del proyecto como un recurso de agrupación. Para agregar un archivo a un proyecto, haga lo siguiente:

  1. Haga clic con el botón derecho en la carpeta Recursos del proyecto en el Panel de solución y seleccione Agregar>archivos...:

    Adding a file

  2. En el cuadro de diálogo Agregar archivos , seleccione los archivos de imágenes que se van a agregar al proyecto, seleccione BundleResource la acción Invalidar compilación y haga clic en el botón Abrir :

    Selecting the files to add

  3. Si los archivos aún no están en la carpeta Resources , se le preguntará si desea copiar, mover o vincular los archivos. Elija cuáles se adapten a sus necesidades, normalmente que serán Copy:

    Selecting the add action

  4. Los nuevos archivos se incluirán en el proyecto y se leerán para su uso:

    The new image files added to the Solution Pad

  5. Repita el proceso para los archivos de imagen necesarios.

Puede usar cualquier archivo png, jpg o pdf como imagen de origen en la aplicación Xamarin.Mac. En la sección siguiente, veremos cómo agregar versiones de alta resolución de nuestras imágenes e iconos para admitir mac basados en Retina.

Importante

Si va a agregar imágenes a la carpeta Recursos , puede dejar la acción Invalidar compilación establecida en Predeterminado. La acción de compilación predeterminada para esta carpeta es BundleResource.

Proporcionar versiones de alta resolución de todos los recursos gráficos de la aplicación

Cualquier recurso gráfico que agregue a una aplicación de Xamarin.Mac (iconos, controles personalizados, cursores personalizados, ilustraciones personalizadas, etc.) debe tener versiones de alta resolución además de sus versiones de resolución estándar. Esto es necesario para que la aplicación se vea mejor cuando se ejecute en un ordenador Mac equipado con pantalla Retina.

Adopción de la convención de nomenclatura de @2x

Importante

Apple ha dejado de usar este método para trabajar con imágenes en una aplicación macOS. En su lugar, debes usar Asset Catalog Image Sets para administrar las imágenes de la aplicación.

Al crear las versiones estándar y de alta resolución de una imagen, siga esta convención de nomenclatura para el par de imágenes al incluirlas en el proyecto de Xamarin.Mac:

  • Extensión ImageName.filename-extension de resolución - estándar (ejemplo: tags.png)
  • Extensión de alta resolución - ImageName@2x.filename (ejemplo: ) tags@2x.png

Cuando se agrega a un proyecto, aparecerán de la siguiente manera:

The image files in the Solution Pad

Cuando se asigna una imagen a un elemento de interfaz de usuario en interface Builder, simplemente elegirá el archivo en imageName.formato de extensión de nombredearchivo (ejemplo: tags.png). Lo mismo para usar una imagen en el código de C#, seleccionará el archivo en ImageName.formato de extensión de nombredearchivo.

Cuando se ejecuta la aplicación Xamarin.Mac en un equipo Mac, ImageName.la imagen de formato filename-extension se usará en pantallas de resolución estándar, la ImageName@2x.filenameimagen -extension se seleccionará automáticamente en las bases mac de la pantalla retina.

Uso de imágenes en el Generador de interfaces

Cualquier recurso de imagen que haya agregado a la carpeta Resources del proyecto de Xamarin.Mac y haya establecido la acción de compilación en BundleResource se mostrará automáticamente en interface Builder y se puede seleccionar como parte de un elemento de interfaz de usuario (si controla imágenes).

Para usar una imagen en el generador de interfaces, haga lo siguiente:

  1. Agregue una imagen a la carpeta Resources con una acción de compilación de BundleResource:

    An image resource in the Solution Pad

  2. Haga doble clic en el archivo Main.storyboard para abrirlo para editarlo en el Generador de interfaces:

    Editing the main storyboard

  3. Arrastre un elemento de interfaz de usuario que tome imágenes a la superficie de diseño (por ejemplo, un elemento de la barra de herramientas de imágenes):

    Editing a toolbar item

  4. Seleccione la imagen que agregó a la carpeta Recursos en la lista desplegable Nombre de imagen:

    Selecting an image for a toolbar item

  5. La imagen seleccionada se mostrará en la superficie de diseño:

    The image being displayed in the Toolbar editor

  6. Guarde los cambios y vuelva a Visual Studio para Mac para sincronizar con Xcode.

Los pasos anteriores funcionan para cualquier elemento de interfaz de usuario que permita que su propiedad de imagen se establezca en el Inspector de atributos. De nuevo, si has incluido una versión @2x del archivo de imagen, se usará automáticamente en mac basados en Retina Display.

Importante

Si la imagen no está disponible en la lista desplegable Nombre de imagen, cierre el proyecto .storyboard en Xcode y vuelva a abrirlo desde Visual Studio para Mac. Si la imagen sigue sin estar disponible, asegúrese de que su acción de compilación es BundleResource y que la imagen se ha agregado a la carpeta Resources .

Uso de imágenes en código de C#

Al cargar una imagen en memoria mediante código de C# en la aplicación de Xamarin.Mac, la imagen se almacenará en un NSImage objeto . Si el archivo de imagen se ha incluido en el paquete de aplicaciones de Xamarin.Mac (incluido en recursos), use el código siguiente para cargar la imagen:

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

El código anterior usa el método estático ImageNamed("...") de la NSImage clase para cargar la imagen dada en la memoria desde la carpeta Resources , si no se encuentra la imagen, null se devolverá. Al igual que las imágenes asignadas en interface Builder, si has incluido una versión @2x del archivo de imagen, se usará automáticamente en mac basados en Retina Display.

Para cargar imágenes fuera del paquete de la aplicación (desde el sistema de archivos Mac), use el código siguiente:

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

Trabajar con imágenes de plantilla

En función del diseño de la aplicación macOS, puede haber ocasiones en las que necesite personalizar un icono o imagen dentro de la interfaz de usuario para que coincida con un cambio en la combinación de colores (por ejemplo, en función de las preferencias del usuario).

Para lograr este efecto, cambie el modo de representación del recurso de imagen a Imagen de plantilla:

Setting a template image

En el Generador de interfaces de Xcode, asigne el recurso de imagen a un control de interfaz de usuario:

Selecting an image in Xcode's Interface Builder

También puede establecer el origen de la imagen en el código:

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

Agregue la siguiente función pública al controlador de vista:

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

Especialmente con la llegada del modo oscuro en macOS Mojave, es importante evitar la LockFocus API al volver a representar objetos representados NSImage personalizados. Estas imágenes se convierten en estáticas y no se actualizarán automáticamente para tener en cuenta los cambios de apariencia o densidad de visualización.

Al emplear el mecanismo basado en el controlador anterior, la nueva representación de las condiciones dinámicas se producirá automáticamente cuando NSImage se hospede, por ejemplo, en .NSImageView

Por último, paraintar una imagen de plantilla, llame a esta función en la imagen para colorear:

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

Uso de imágenes con vistas de tabla

Para incluir una imagen como parte de la celda en , NSTableViewdeberá cambiar cómo devuelven los datos el método de NSTableViewDelegate'sGetViewForItem la vista de tabla para usar en NSTableCellView lugar del típico NSTextField. Por ejemplo:

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

Hay algunas líneas de interés aquí. En primer lugar, para las columnas que queremos incluir una imagen, creamos una nueva NSImageView de la ubicación y el tamaño necesarios, también creamos una nueva NSTextField y colocamos su posición predeterminada en función de si usamos o no una imagen:

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

En segundo lugar, es necesario incluir la nueva vista de imagen y el campo de texto en el elemento primario NSTableCellView:

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

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

Por último, es necesario indicar al campo de texto que puede reducirse y crecer con la celda vista de tabla:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Ejemplo:

An example of displaying an image in an app

Para obtener más información sobre cómo trabajar con vistas de tabla, consulte nuestra documentación sobre vistas de tabla .

Uso de imágenes con vistas de esquema

Para incluir una imagen como parte de la celda en , NSOutlineViewdeberá cambiar cómo devuelven los datos el método de NSTableViewDelegate'sGetView la vista esquema para usar en NSTableCellView lugar del típico NSTextField. Por ejemplo:

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

Hay algunas líneas de interés aquí. En primer lugar, para las columnas que queremos incluir una imagen, creamos una nueva NSImageView de la ubicación y el tamaño necesarios, también creamos una nueva NSTextField y colocamos su posición predeterminada en función de si usamos o no una imagen:

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

En segundo lugar, es necesario incluir la nueva vista de imagen y el campo de texto en el elemento primario NSTableCellView:

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

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

Por último, es necesario indicar al campo de texto que puede reducirse y crecer con la celda vista de tabla:

view.TextField.AutoresizingMask = NSViewResizingMask.WidthSizable;

Ejemplo:

An example of an image being displayed in an Outline View

Para obtener más información sobre cómo trabajar con vistas de esquema, consulte nuestra documentación de vistas de esquema.

Resumen

En este artículo se ha realizado un vistazo detallado al trabajo con imágenes e iconos en una aplicación de Xamarin.Mac. Hemos visto los diferentes tipos y usos de imágenes, cómo usar imágenes e iconos en el Generador de interfaces de Xcode y cómo trabajar con imágenes e iconos en código de C#.