Resumen del capítulo 13. Mapas de bits

Nota:

Este libro se publicó en la primavera de 2016 y no se ha actualizado desde entonces. Gran parte del libro sigue siendo útil, pero algunos de los materiales están anticuados y algunos temas ya no son completamente correctos o completos.

El elemento Xamarin.FormsImage muestra un mapa de bits. Todas las plataformas de Xamarin.Forms admiten los formatos de archivo JPEG, PNG, GIF y BMP.

Los mapas de bits de Xamarin.Forms provienen de cuatro lugares:

  • A través de la web como se especifica en una dirección URL
  • Incrustados como un recurso en la biblioteca compartida
  • Incrustados como un recurso en proyectos de la aplicación de plataforma
  • Desde cualquier parte a la que se pueda hacer referencia con un objeto Stream de .NET, como MemoryStream.

Los recursos de mapa de bits de la biblioteca compartida son independientes de la plataforma, mientras que los recursos de mapa de bits de los proyectos de plataforma son específicos de la plataforma.

Nota:

El texto del libro hace referencia a las bibliotecas de clases portables, que se han reemplazado por las bibliotecas .NET Standard. Todo el código de ejemplo del libro se ha convertido para usar las bibliotecas .NET estándar.

El mapa de bits se especifica mediante el establecimiento de la propiedad Source de Image en un objeto de tipo ImageSource, una clase abstracta con tres derivados:

  • UriImageSource para acceder a un mapa de bits a través de la web en función de un objeto Uri establecido en su propiedad Uri.
  • FileImageSource para acceder a un mapa de bits almacenado en un proyecto de aplicación de plataforma en función de una ruta de acceso a archivos y carpetas establecida en su propiedad File.
  • StreamImageSource para cargar un mapa de bits mediante un objeto Stream de .NET especificado por medio de la devolución de un elemento Stream desde un elemento Func establecido en su propiedad Stream.

Como alternativa (y de forma más común), se pueden usar los siguientes métodos estáticos de la clase ImageSource, todos los cuales devuelven objetos ImageSource:

No hay ninguna clase equivalente de los métodos Image.FromResource. La clase UriImageSource es útil si necesita controlar el almacenamiento en caché. La clase FileImageSource es útil en XAML. StreamImageSource es útil para la carga asincrónica de objetos Stream, mientras que ImageSource.FromStream es sincrónico.

Mapas de bits independientes de la plataforma

El proyecto WebBitmapCode carga un mapa de bits a través de la web mediante ImageSource.FromUri. El elemento Image se establece en la propiedad Content de ContentPage, por lo que se limita al tamaño de la página. Con independencia del tamaño del mapa de bits, un elemento Image restringido se ajusta al tamaño de su contenedor y el mapa de bits se muestra en su tamaño máximo dentro del elemento Image mientras se mantiene la relación de aspecto del mapa de bits. Las áreas de Image más allá del mapa de bits se pueden colorear con BackgroundColor.

El ejemplo WebBitmapXaml es similar, pero simplemente establece la propiedad Source en la dirección URL. La conversión se controla mediante la clase ImageSourceConverter.

Ajuste y relleno

Puede controlar cómo se ajusta el mapa de bits mediante el establecimiento de la propiedad Aspect de Image en uno de los siguientes miembros de la enumeración Aspect:

  • AspectFit: respeta la relación de aspecto (valor predeterminado).
  • Fill: rellena el área, no respeta la relación de aspecto.
  • AspectFill: rellena el área pero respeta la relación de aspecto, al recortar parte del mapa de bits.

Recursos incrustados

Puede agregar un archivo de mapa de bits a una PCL o a una de sus carpetas. Asígnele una acción de compilación de EmbeddedResource. En el ejemplo ResourceBitmapCode se muestra cómo utilizar ImageSource.FromResource para cargar el archivo. El nombre del recurso que se pasa al método consta del nombre del ensamblado, seguido de un punto, seguido del nombre de carpeta opcional y un punto, seguido del nombre de archivo.

El programa establece las propiedades VerticalOptions y HorizontalOptions de Image en LayoutOptions.Center, lo que hace que el elemento Image quede sin restricciones. Image y el mapa de bits tienen el mismo tamaño:

  • En iOS y Android, Image tiene el tamaño de píxel del mapa de bits. Hay una asignación uno a uno entre los píxeles del mapa de bits y los píxeles de la pantalla.
  • En la Plataforma universal de Windows, Image tiene el tamaño de píxel del mapa de bits en unidades independientes del dispositivo. En la mayoría de los dispositivos, cada píxel de mapa de bits ocupa varios píxeles de pantalla.

En el ejemplo StackedBitmap se coloca un elemento Image en un elemento StackLayout vertical en XAML. Una extensión de marcado con el nombre ImageResourceExtension ayuda a hacer referencia al recurso incrustado en XAML. Esta clase solo carga los recursos del ensamblado en el que se encuentra, por lo que no se puede colocar en una biblioteca.

Más sobre el ajuste de tamaño

A menudo es conveniente cambiar el tamaño de los mapas de bits de forma coherente en todas las plataformas. Experimentando con StackedBitmap, puede establecer un elemento WidthRequest en el elemento Image de un elemento StackLayout vertical para que el tamaño sea coherente entre las plataformas, pero solo puede reducir el tamaño con esta técnica.

También puede establecer HeightRequest para que los tamaños de imagen sean coherentes en las plataformas, pero el ancho restringido del mapa de bits limitará la versatilidad de esta técnica. En el caso de una imagen de un elemento StackLayout vertical, se debe evitar HeightRequest.

El mejor enfoque es comenzar con un mapa de bits más ancho que el ancho del teléfono en unidades independientes del dispositivo y establecer WidthRequest en un ancho deseado en unidades independientes del dispositivo. Esto se muestra en el ejemplo DeviceIndBitmapSize.

En MadTeaParty se muestra el capítulo 7 de las Aventuras de Alicia en el País de las Maravillas de Lewis Carroll con las ilustraciones originales de John Tenniel:

Captura de pantalla triple de la fiesta de té loco

Examinar y esperar

El ejemplo ImageBrowser permite al usuario examinar las imágenes de existencias almacenadas en el sitio web de Xamarin. Se usa la clase WebRequest de .NET para descargar un archivo JSON con la lista de mapas de bits.

Nota:

Los programas de Xamarin.Forms deben usar HttpClient en lugar de WebRequest para acceder a los archivos a través de Internet.

El programa usa un elemento ActivityIndicator para indicar que algo pasa. A medida que se carga el mapa de bits, la propiedad IsLoading de solo lectura Image es true. La propiedad IsLoading está respaldada por una propiedad enlazable, por lo que se desencadena un evento PropertyChanged cuando esa propiedad cambia. El programa adjunta un controlador a este evento y usa la configuración actual de IsLoaded para establecer la propiedad IsRunning de ActivityIndicator.

Mapas de bits de streaming

El método ImageSource.FromStream crea un elemento ImageSource en función de Stream de .NET. Se debe pasar al método un objeto Func que devuelva un objeto Stream.

Acceso a las secuencias

En el ejemplo BitmapStreams se muestra cómo usar el método ImaageSource.FromStream para cargar un mapa de bits almacenado como un recurso incrustado, y para cargar un mapa de bits en la web.

Generación de mapas de bits en tiempo de ejecución

Todas las plataformas Xamarin.Forms admiten el formato de archivo BMP sin comprimir, que es fácil de construir en el código y luego almacenar en un elemento MemoryStream. Esta técnica permite la creación algorítmica de mapas de bits en tiempo de ejecución, tal y como se implementa en la clase BmpMaker de la biblioteca deXamarin.FormsBook.Toolkit.

El ejemplo DiyGradientBitmap de "Hágalo usted mismo" muestra el uso de BmpMaker para crear un mapa de bits con una imagen de degradado.

Mapas de bits específicos de la plataforma

Todas las plataformas Xamarin.Forms permiten almacenar mapas de bits en los ensamblados de aplicación de la plataforma. Cuando una aplicación Xamarin.Forms los recupera, estos mapas de bits de plataforma son de tipo FileImageSource. Úselos para:

Los ensamblados de plataforma ya contienen mapas de bits para iconos y pantallas de presentación:

  • En el proyecto de iOS, en la carpeta Resources.
  • En el proyecto de Android, en las subcarpetas de la carpeta Resources.
  • En los proyectos de Windows, en la carpeta Assets (aunque las plataformas de Windows no restringen los mapas de bits a esa carpeta).

En el ejemplo PlatformBitmaps se usa código para mostrar un icono de los proyectos de aplicación de la plataforma.

Resoluciones del mapa de bits

Todas las plataformas permiten almacenar varias versiones de imágenes de mapa de bits para diferentes resoluciones de dispositivos. En tiempo de ejecución, la versión correcta se carga en función de la resolución de la pantalla del dispositivo.

En iOS, estos mapas de bits se diferencian por un sufijo en el nombre de archivo:

  • Ningún sufijo para dispositivos de 160 ppp (1 píxel para la unidad independiente del dispositivo)
  • Sufijo "@2x" para dispositivos de 320 DPI (2 píxeles para la DIU)
  • Sufijo "@3x" para dispositivos de 480 DPI (3 píxeles para la DIU)

Un mapa de bits que se vaya a mostrar como una pulgada cuadrada existirá en tres versiones:

  • MyImage.jpg en un cuadrado de 160 píxeles
  • MyImage@2x.jpg en un cuadrado de 320 píxeles
  • MyImage@3x.jpg en un cuadrado de 480 píxeles

El programa haría referencia a este mapa de bits como MyImage.jpg, pero la versión correcta se recupera en tiempo de ejecución en función de la resolución de la pantalla. Si no está restringido, el mapa de bits siempre se representará en 160 unidades independientes del dispositivo.

En el caso de Android, los mapas de bits se almacenan en varias subcarpetas de la carpeta Resources:

  • drawable-ldpi (ppp bajo) para dispositivos de 120 ppp (0,75 píxeles para la DIU)
  • drawable-mdpi (medio) para dispositivos de 160 ppp (1 píxel para la DIU)
  • drawable-mdpi (alto) para dispositivos de 240 ppp (1,5 píxeles para la DIU)
  • drawable-mdpi (muy alto) para dispositivos de 320 ppp (2 píxeles para la DIU)
  • drawable-mdpi (muy muy alto) para dispositivos de 480 ppp (3 píxeles para la DIU)
  • drawable-mdpi (tres muy alto) para dispositivos de 640 ppp (4 píxeles para la DIU)

En el caso de un mapa de bits que se vaya a representar en una pulgada cuadrada, las distintas versiones del mapa de bits tendrán el mismo nombre pero con un tamaño diferente, y se almacenarán en estas carpetas:

  • drawable-ldpi/MyImage.jpg en un cuadrado de 120 píxeles
  • drawable-mdpi/MyImage.jpg en un cuadrado de 160 píxeles
  • drawable-hdpi/MyImage.jpg en un cuadrado de 240 píxeles
  • drawable-xhdpi/MyImage.jpg en un cuadrado de 320 píxeles
  • drawable-xxhdpi/MyImage.jpg en un cuadrado de 480 píxeles
  • drawable-xxxhdpi/MyImage.jpg en un cuadrado de 640 píxeles

El mapa de bits siempre se representará en 160 unidades independientes del dispositivo. (La plantilla de la solución Xamarin.Forms estándar solo incluye las carpetas hdpi, xhdpi y xxhdpi).

El proyecto UWP admite un esquema de nomenclatura de mapa de bits que consta de un factor de escala en píxeles por unidad independiente del dispositivo como un porcentaje, por ejemplo:

  • MyImage.scale-200.jpg en un cuadrado de 320 píxeles

Solo algunos porcentajes son válidos. Los programas de ejemplo de este libro incluyen solo imágenes con sufijos scale-200, pero las plantillas de soluciones actuales de Xamarin.Forms incluyen scale-100, scale-125, scale-150 y scale-400.

Al agregar mapas de bits a los proyectos de la plataforma, la acción de compilación debe ser:

  • iOS: BundleResource
  • Android: AndroidResource
  • UWP: Contenido

En el ejemplo ImageTap se crean dos objetos tipo botón que constan de elementos Image con TapGestureRecognizer instalado. El objetivo es que los objetos sean de un pulgada cuadrada. La propiedad Source de Image se establece mediante objetos OnPlatform y On para hacer referencia a nombres de archivo potencialmente diferentes en las plataformas. Las imágenes de mapa de bits incluyen números que indican su tamaño en píxeles, por lo que puede ver qué tamaño de mapa de bits se recupera y se representa.

Barras de herramientas y sus iconos

Uno de los usos principales de los mapas de bits específicos de la plataforma es la barra de herramientas de Xamarin.Forms, que se construye mediante la adición de objetos ToolbarItem a la colección ToolbarItems definida por Page. ToobarItem se deriva de MenuItem del que hereda algunas propiedades.

Las dos propiedades ToolbarItem más importantes son:

  • Text para el texto que puede aparecer en función de la plataforma y Order
  • Icon de tipo FileImageSource para la imagen que puede aparecer en función de la plataforma y Order
  • Order de tipo ToolbarItemOrder, una enumeración con tres miembros, Default, Primary y Secondary.

El número de elementos Primary debe estar limitado a tres o cuatro. Debe incluir un valor Text para todos los elementos. En la mayoría de las plataformas, solo los elementos Primary requieren un objeto Icon, pero Windows 8.1 requiere un objeto Icon para todos. Los iconos deben tener 32 unidades cuadradas independientes del dispositivo. El tipo FileImageSource indica que son específicos de la plataforma.

ToolbarItem activa un evento Clicked cuando se pulsa, de forma muy parecida a una Button. ToolbarItem también admite propiedades Command y CommandParameter que se usan a menudo en conexión con MVVM. (Consulte el Capítulo 18, MVVM).

Tanto iOS como Android requieren que una página que muestre una barra de herramientas sea NavigationPage o una página a la que se haya ido mediante NavigationPage. El programa ToolbarDemo establece la propiedad MainPage de su clase App en el constructor NavigationPage con un argumento ContentPage, y muestra el controlador de eventos y la construcción de una barra de herramientas.

Imágenes de botón

También puede usar mapas de bits específicos de la plataforma para establecer la propiedad Image de Button en un mapa de bits de 32 unidades cuadradas independientes del dispositivo, como se muestra en el ejemplo ButtonImage.

Nota:

El uso de imágenes en botones se ha mejorado. Consulte Uso de mapas de bits con botones.