Compartir a través de


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 Interface Builder 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 tablas (NSTableView o NSOutlineView), las imágenes se pueden usar en una celda Image (NSImageCell).
  • elemento de barra de herramientas: las imágenes se pueden agregar a una barra de herramientas (NSToolbar) como elemento de barra de herramientas de imagen (NSToolbarItem).
  • Icono de lista de origen: como parte de una lista de origen (un NSOutlineViewcon formato especial ).
  • icono de aplicación: se puede agrupar una serie de imágenes en un conjunto de .icns y usarse como icono de la aplicación. Consulte nuestra documentación de 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.

Una ejecución de ejemplo de la aplicación

En este artículo, trataremos los conceptos básicos de trabajar con imágenes e iconos en una aplicación de Xamarin.Mac. Es muy recomendable leer primero el artículo Hello, Mac, en concreto las secciones Introducción a Xcode e Interface Builder y Salidas y acciones, ya que tratan los conceptos clave y las técnicas que se usan 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 forme 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 carpeta Card al proyecto y una subcarpeta 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 del 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:

    Selección de Assets.xcassets

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

    Adición de un nuevo conjunto de imágenes

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

    Selección del nuevo conjunto de imágenes

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

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

    Edición del nombre del conjunto de imágenes

Se ha agregado una clase especial Vector a los Conjuntos de imágenes que nos permite incluir una imagen vectorial con formato PDF en el conjunto en lugar de incluir archivos de mapa de bits individuales en las diferentes resoluciones. Con este método, se proporciona un único archivo vectorial para la resolución de @1x (con formato de archivo PDF vectorial) y @2x y las versiones @3x del archivo se generarán en tiempo de compilación e incluirán en el paquete de la aplicación.

Interfaz del editor del conjunto de imágenes

Por ejemplo, si incluye un archivo MonkeyIcon.pdf 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 de 300 píxeles 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 Interface Builder de Xcode, simplemente puede seleccionar el nombre del conjunto en la lista desplegable de inspector de atributos:

Selección de un conjunto de imágenes en Interface Builder de Xcode

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 Nombrepara la colección y haga clic en el botón Nuevo:

    Adición de un nuevo catálogo de recursos

Desde aquí puede trabajar con la colección del mismo modo que con la colección Assets.xcassets incluida de forma predeterminada 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. Debe usar Conjuntos de imágenes del catálogo de recursos para administrar las imágenes de la aplicación en su lugar.

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 de recursos 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 de y seleccione Agregar>Agregar archivos...:

    Adición de un archivo

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

    Selección de archivos que se van a agregar

  3. Si los archivos aún no están en la carpeta Recursos, se le preguntará si desea Copiar, Mover o Vincular los archivos. Elija cuáles se adapten a sus necesidades, que normalmente seráncopiar:

    Selección de la acción agregar

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

    Los nuevos archivos de imagen agregados al Panel de solución

  5. Repita el proceso para los archivos de imagen que necesite.

Puede usar cualquier archivo png, jpg o pdf como imagen de origen en la aplicación Xamarin.Mac. En la siguiente sección, 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 carpetaRecursos, 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. Debe usar Conjuntos de imágenes del catálogo de recursos para administrar las imágenes de la aplicación en su lugar.

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:

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

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

Archivos de imagen en el Panel de solución

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 nombre de archivo (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 nombre de archivo.

Cuando se ejecuta la aplicación Xamarin.Mac en un equipo Mac, ImageName.la imagen formato de extensión de nombre de archivo. se usará en pantallas de resolución estándar, la ImageName@2x.filenameextensión de imagen se seleccionará automáticamente en las bases Mac de la pantalla Retina.

Uso de imágenes en Interface Builder

Cualquier recurso de imagen que haya agregado a la carpeta Recursos 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 Recursos con una acción de compilación de BundleResource:

    Un recurso de imagen en el Panel de solución

  2. Haga doble clic en el archivo Main.storyboard para abrirlo para editarlo en Interface Builder:

    Edición del guion gráfico principal

  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):

    Edición de un elemento de barra de herramientas

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

    Selección de una imagen para un elemento de barra de herramientas

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

    Imagen que se muestra en el editor de la barra de herramientas

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

Los pasos anteriores funcionan para cualquier elemento de interfaz de usuario que permita establecer su propiedad de imagen en el Inspector de atributos. De nuevo, si ha incluido una versión @2x del archivo de imagen, se usará automáticamente en Macs 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 lo estáBundleResource y de que la imagen se ha agregado a la carpeta Recursos.

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 objeto NSImage. 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 ImageNamed("...") método estático de la clase NSImage para cargar la imagen dada en la memoria desde la carpeta Recursos, si la imagen no se encuentra, nullse devolverá. Al igual que las imágenes asignadas en Interface Builder, si ha incluido una versión @2x del archivo de imagen, se usará automáticamente en Macs 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:

Establecimiento de una imagen de plantilla

En Interface Builder de Xcode, asigne el recurso de imagen a un control de interfaz de usuario:

Selección de una imagen en Interface Builder de Xcode

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 API LockFocus al volver a representar objetos 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 controladores descrito anteriormente, la nueva renderización para condiciones dinámicas se producirá automáticamente cuando el NSImagese hospede, por ejemplo, en un NSImageView.

Por último, para colorear una imagen de plantilla, llame a esta función en la imagen a 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 una NSTableView, tendrá que cambiar la forma en que el método NSTableViewDelegate'sGetViewForItem de la vista de tabla devuelve los datos para usar NSTableCellView en lugar del habitual 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 en las que queremos incluir una imagen, creamos una nueva NSImageView del tamaño y la ubicación 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 NSTableCellViewprimario :

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:

Ejemplo de visualización de una imagen en una aplicación

Para obtener más información sobre cómo trabajar con vistas de tabla, consulte nuestra documentación de 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 NSTableCellView en lugar del habitual 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 en las que queremos incluir una imagen, creamos una nueva NSImageView del tamaño y la ubicación 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 NSTableCellViewprimario :

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:

Ejemplo de una imagen que se muestra en una vista esquema

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 tratado en detalle cómo trabajar 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 Interface Builder de Xcode y cómo trabajar con imágenes e iconos en código de C#.