[Xamarin.Forms] Mejorar el rendimiento en el tiempo de arranque

Introducción

Además de cuidar detalles como la funcionalidad o la apariencia visual de nuestra aplicación, nuestra aplicación debe funcionar correctamente bajo todas las condiciones en todos los dispositivos para la que sea lanzada.

Un punto importante a revisar siempre suele ser, el tiempo de arranque de la aplicación.

¿Conoces conceptos como AOT?, ¿fast renderers?. En este artículo vamos a repasar algunos conceptos que podemos aplicar para tener un impacto positivo en los tiempos de arranque de la aplicación.

XAMLC

Si defines la interfaz de usuario de la aplicación Xamarin.Forms con XAML tienes la opción de utilizar XamlCompilationOptions.

Cuenta con dos valores:

Compile.

  • Acelera la carga de elementos visuales.
  • Reduce el tamaño del paquete.
  • La compilación (AOT) es más larga.

Skip.

  • Valor por defecto para mantener retocompatibilidad con versiones antiguas de Xamarin.Forms.
  • No hay validación en tiempo de ejecución de XAML.

Ejemplo de uso:

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

La diferencia:

Rendimiento con XAMLC

NOTA: Resultado obtenido tras 5 mediciones utilizando Android.

Fast Renderers

Hablamos de cambios realizados en Xamarin.Forms con el objetivo de reducir a mínimos el número de operaciones y cálculos a realizar para renderizar el control y gestionar su tamaño y posición.

Hasta ahora, la mayoría de los renderers en Android se componían de dos vistas:

  • Control nativo, como Button.
  • Un contenedor ViewGroup que se encargaba de controlar aspectos como los gestos, etc.

Sin embargo, este enfoque tiene una implicación directa en el rendimiento al crear dos elementos por cada control, lo que resulta en un árbol visual más complejo, requiere más memoria y más capacidad de procesamiento para representar en la pantalla.

Los Fast Renderers reducen la inflación y los tiempos para el renderizado de un control de Xamarin.Forms.

Veamos un ejemplo de jerarquía de elementos sin utilizar Fast Renderers:

Jerarquía sin utilizar Fast Renderers

Y utilizando Fast Renderers:

Jerarquía utilizando Fast Renderers

La diferencia:

Rendimiento con Fast Renderers

Los Fast Renderers están disponibles para los siguientes controles de Xamarin.Forms en Android:

  • Button
  • Image
  • Label
  • Frame

Desde Xamarin.Forms 4.0 se utilizan por defecto los Fast Renderers. Si quieres no utilizarlos, puedes hacerlo:

Forms.SetFlags("UseLegacyRenderers");

Configuración de la App

La opción compilación AOT habilita la compilación Ahead Of Time de los ensamblados. Cuando esta opción está habilitada, la sobrecarga de inicio Just-In-Time (JIT) se minimiza al precompilar ensamblados antes del tiempo de ejecución. El código nativo resultante se incluye en el paquete (APK) junto con los ensamblados sin compilar. Esto da como resultado un tiempo de inicio de la aplicación más reducido, pero a costa de tamaños APK más grandes.

A costa de tiempos de compilación más lentos, el compilador de optimización de LLVM debe crear un código compilado más pequeño y rápido (en las pruebas, efectivamente conseguimos un paquete más ligero aunque no tenemos reducción en lso tiempos de arranque de la aplicación).

A continuación, una comparativa del tiempo de arranque de la aplicación en milisegundos entre el uso de JIT, AOT y AOT junto con la opciónde optimización de LLVM:

Rendimiento con diferentes configuraciones

Como se puede observar, la reducción de tiempo usando AOT es notoria pero…¿cómo afecta al tamaño del paquete?.

Comparativa del peso del paquete

Puedes encontrar los ejemplos utilizados así como archivos Excel con las medidas en GitHub:

Ver GitHub

Más información

[Xamarin.Forms] Mejorar el rendimiento al trabajar con imágenes

Introducción

El uso de imágenes en aplicaciones móviles es habitual. Es un elemento clave a la hora de conseguir buenos resultados visuales. Sin embargo, también suelen ser uno de los puntos clave que impactan en el rendimiento de la aplicación. Problemas como:

  • Alto consumo de memoria.
  • Bloqueo de la UI (carga de imágenes en el hilo de UI, etc).
  • Etc.

En este artículo, vamos a realizar comparaciones en el rendimiento del control Image de Xamarin.Forms entre diferentes versiones, así como una comparativa con FFImageLoading y GlideX.

Para realizar las comaparativas vamos a necesitar un ejemplo y algo de código para obtener información. Nuestro ejemplo va a ser una versión modificada del gran ejemplo realizado por Jonathan Peppers en Glidex.

El ejemplo

A la hora de medir, vamos a utilizar:

System.Diagnostics.Process.GetCurrentProcess().WorkingSet64

Para obtener la cantidad de bytes que se estan consumiendo.

Imágenes en Xamarin.Forms

El control Image de Xamarin.Forms permite la carga de imágenes desde diferentes fuentes (URL, recurso incrustrado, etc.). El rendimiento general es correcto aunque con mejoras (mejoras en la cache, reutilizar recursos, etc.).

Desde la versión 4.0 de Xamarin.Forms se han comenzado a realizar mejoras en la gestión de imágenes. Pero…¿realmente tenemos mejora?.

Para contestar de forma correcta, vamos a cargar 100 imágenes en un Grid (evitamos usar listados y reutilización de celdas para conseguir tener un volumen elevado de imágenes en el árbol visual y en memoria).

Lanzamos la aplicación tanto utilizando la versión 3.6 como la versión 4.0. Tras lanzar la aplicación 5 veces y hacer la media de la memoria consumida:

Mejoras en la gestión de imágenes en Xamarin.Forms 4.0

Xamarin.Forms 4.0 consume una media de un 15% menos de memoria con respecto a la versión 3.6. Una buena mejora en la gestión de imágenes pero…¿podemos conseguir mejorar más al gestionar las imágenes?.

FFImageLoading

FFImageLoading es una de las librerías de la comunidad más usadas y más recomendadas. Esta librería tiene como objetivo cargar imágenes de la forma más eficiente posible. Entre las características principales (y que tienen impacto en el rendimiento):

  • Cache de imágenes en memoria y disco.
  • Múltiples imágenes usando el mismo origen (url, ruta, recurso) usarán solo un mapa de bits que se almacena en caché en memoria (menos uso de memoria).
  • Placeholders de carga y error.
  • Las imágenes se pueden ajustar automáticamente a un tamaño especificado (menos uso de memoria).
  • Etc.

Tras realizar benchmarking entre FFImageLoading y el control Image de Xamarin.Forms, gracias a las opciones de cache, ajuste de tamaño, etc., obtenemos mejor rendimiento con FFImageLoading.

GlideX

GlideX.Forms nos permite utilizar Glide (Una librería de carga y almacenamiento de imágenes para Android enfocada en el rendimiento) en Xamarin.Forms Android.

Al igual que anteriormente, hemos realizado benchmarking en Android entre el control Image de Xamarin.Forms, FFImageLoading y GlideX. GlideX es la opción más óptima en Android superando levemente a FFImageLoading y con una diferencia más considerable con respecto al control Image.

IImageSourceHandler

Así que, GlideX es más eficiente en Android pero…¿que usamos en iOS?. Podríamos utilizar FFImageLoading directamente en ambas plataformas, es una buena opción. Sin embargo, podríamos usar FFImageLoading en iOS y GlideX en Android.

Desde Xamarin.Forms 2.3.5, tenemos la interfaz IImageSourceHandler. Permite implementar ImageSource en la plataforma.

Ejemplo básico (en iOS):

public class ImageSourceHandler : IImageSourceHandler
{
     public Task<UIImage> LoadImageAsync(
          ImageSource imageSource,
          CancellationToken cancellationToken = new CancellationToken(),
          float scale = 1)
     {
          ...
     }
}

Podemos gestionar la fuente de imágenes de forma sencilla, utilizando en cada plataforma la opción que necesitemos. Jean-Marie Alfonsi ha creado Xamarin.Forms.ImageSourceHandlers con esta misma idea. Su uso es sencillo.

En Android, vamos a utilizar GlideX. Necesitaremos la inicialización de la librería.

Android.Glide.Forms.Init();

Mientras que en iOS, vamos a usar FFImageLoading:

FFImageLoading.FormsHandler.Init();

Benchmarking

Llegados a este punto, tenemos todo lo necesario para obtener datos y sacar algunas conclusiones. La gestión de imágenes es un punto importante a la hora de crear aplicaciones móviles. En Xamarin.Forms se continua mejorando y lo podemos ver en los datos obtenidos comparando la versión 3.6 y la versión 4.0.

A continuación, una comparativa en Android de la misma aplicación cargando 100 imágenes utilizando el control Image de Xamarin.Forms, FFImageLoading y GlideX:

La comparativa

NOTA: Los datos salen de la media de 5 medidas.

Puedes encontrar los ejemplos utilizados así como archivos Excel con las medidas en GitHub:

Ver GitHub

Otras recomendaciones

Podemos aplicar otra serie de acciones para mejorar considerablemente el rendimiento a la hora de trabajar con imágenes:

  • Evitar la necesidad de reducir el tamaño de imágenes (memoria consumida) en el dispositivo. Si tenemos control sobre el servidor proveedor de las imágenes, gestionar las imágenes en el mismo.
  • Además del punto anterior, reducir las imágenes locales utilizadas. Podemos conseguirlo de varias formas. Controlando el tamaño (o formato) de la imagen,  o bien, se pueden utilizar servicios como tinypng.

Más información

[Xamarin.Forms UI Challenge] Art News, transiciones entre páginas

Introducción

Volvemos a por un reto de interfaz de usuario con Xamarin.Forms. En este artículo, vamos a tomar como referencia un diseño de Dribbble (por Shirley Yao), que intentaremos replicar con paso a paso.

Art News

Vamos a intentar replicar la UI del diseño paso a paso en Xamarin.Forms.

Los retos del ejemplo

Vamos a replicar dos pantallas con algunos retos, pero la clave del ejemplo es la transición de elementos compartidos entre las dos páginas.

  • Listado horizontal: La llegada de CollectionView es no solo una mejora en el rendimiento a la hora de trabajar con colecciones, también con diferentes Layouts (listados horizontales, GridViews, etc.). En este ejemplo, el número de elementos en el listado horizontal es bajo, por lo que podemos también hacer uso de un sencillo StackLayout y Bindable Layout.
  • Grid de fotos en los detalles: En caso de mostrar un número limitado o concreto de fotos en la galería mostrada en la página de detalles, podría usar un Layout. Probablemente un Grid o FlexLayout. Sin embargo, en caso de no ser limitado, CollectionView nos permite mostrar un número indeterminado de fotos en dos columnas de forma sencilla.
  • Transición entre páginas: Por defecto, no tenemos soporte a transiciones de páginas en Xamarin.Forms. Contamos con dos tipos de transiciones diferentes. Por un lado, las transiciones tradiciones que implican una animación de toda la página al entrar o salir. Por otro lado, tenemos las conocidas como transcisiones de elementos compartidos. En muchas ocasiones, tenemos un elemento visual compartido entre dos páginas (por ejemplo, una imagen) para trasmitir una sensación de fluidez y continuidad. En este ejemplo, veremos ambas opciones. Es necesario crear un Custom Renderer de la NavigationPage para conseguir el objetivo. Por suerte, no partimos de cero, utilizaremos Xamarin.Plugin.SharedTransitions.
  • Animaciones: Necesitamos una sencilla animación de Fade In y translación desde la parte inferior hacia la superior al navegar a la página de detalles (además de la transición). Xamarin.Forms cuenta con una completa Api de animaciones. En el ejemplo usaremos Xamanimation que nos ofrece animaciones prepadas, Storyboard y la posibilidad de usarlo todo desde XAML.

Listado horizontal

Para crear el listado horizontal utilizaremos Bindable Layouts.

<ScrollView 
     Orientation="Horizontal"
     HorizontalScrollBarVisibility="Default"
     VerticalScrollBarVisibility="Never">
     <StackLayout 
          x:Name="Highlights"
          Padding="20, 0, 0, 36"
          Orientation="Horizontal"
          BindableLayout.ItemsSource="{Binding Author.Highlights}">
          <BindableLayout.ItemTemplate>
               <DataTemplate>
                     <Grid
                          x:Name="HighlightTemplate"
                          RowSpacing="0"
                          Style="{StaticResource HighlightStyle}">
                          ...
                    </Grid>
               </DataTemplate>
          </BindableLayout.ItemTemplate>
     </StackLayout>
</ScrollView>

Usamos un scroll horizontal (sin mostrar la barra de scroll vertical) con un StackLayout apilando los elementos horizontalmente. La clave es el uso de las propiedades BindableLayout.ItemsSource y BindableLayout.ItemTemplate.

El resultado:

Listado horizontal

NOTA: En caso de contar con un número de elementos elevado, recuerda que no tenemos virtualización, etc. al usar Bindable Layouts. En dicho caso, es más recomendable utilizar CollectionView.

Grid de fotos en los detalles

El Layout de fotos se puede conseguir de diferentes formas. Probablemente, y ante un número determinado de elementos (un número bajo de elementos) se podría usar un Grid o FlexLayout con Bindable Layouts. Sin embargo, en este caso se ha utilizado CollectionView.

<CollectionView
     Grid.Row="1"
     ItemsSource="{Binding ArtItem.Related}"
     SelectionMode="None"
     InputTransparent="True">
     <CollectionView.ItemsLayout>
           <GridItemsLayout 
                Orientation="Vertical" 
                Span="2"/>
     </CollectionView.ItemsLayout>
     <CollectionView.ItemTemplate>
          <DataTemplate>
               <templates:RelatedContentTemplate />
          </DataTemplate>
     </CollectionView.ItemTemplate>
</CollectionView>

Para mostrar las dos columnas, utilizamos la propiedad ItemsLayout con GridItemsLayout utilizando la propiedad Span para indicar el número de columnas deseadas.

El resultado:

Grid de contenido relacionado

Sencillo, ¿verdad?. La llegada de BindableLayouts y de CollectionView nos permite conseguir resultados que hasta ahora requerían la creación de Custom Controls o Custom Renderers.

Transiciones entre páginas

Llegamos al “plato fuerte” del ejemplo, las transiciones entre páginas. Vamos a utilizar una versión modificada (al momento de escribir este artículo quedan algunas Pull Request pendientea por mergear, aunque los cambios de este ejemplo acabarán estando probablemente en la librería) de Xamarin.Plugin.SharedTransitions.

La idea de la librería es:

  • Custom Renderer de NavigationPage donde permitir las transiciones tradicionales (animación de entrada y salida de una página).
  • Effects que poder aplicar a elementos de la UI para permitir aplicar transiciones de elementos compartidos.

En cualquier página (ContentPage), podemos indicar la transición a utilizar de forma sencilla utilizando el método SetBackgroundAnimation:

SharedTransitionNavigationPage.SetBackgroundAnimation(this, BackgroundAnimation.SlideFromLeft);
SharedTransitionNavigationPage.SetSharedTransitionDuration(this, 500);

Entre las opciones disponibles:

  • Fade
  • Flip
  • SlideFromLeft
  • SlideFromRight
  • SlideFromTop
  • SlideFromBottom

¿Y las transiciones de elementos conectados?

Vamos a ver como utilizarlas. Comenzando añadiendo el namespace XAML necesario:

xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"

En casos básicos, por ejemplo, conectar dos elementos individuales, por ejemplo un botón en dos páginas diferentes, bastará con utilizar la propiedad Tag disponible en la clase Transition.

En caso de querer hacer transiciones entre elementos de una colección como es nuestro caso (imagen correspondiente a una plantilla usada en un Bindable Layout), necesitamos utilizar además de Tag, la propiedad TagGroup.

sharedTransitions:Transition.TagGroup="1"
sharedTransitions:Transition.Tag="{Binding Number}"

NOTA: Cada elemento debe tener un Tag único.

En la página de destino, volvemos a aplicar el mismo Tag utilizado en la página anterior.

sharedTransitions:Transition.Tag="{Binding ArtItem.Number}"

NOTA: No es necesario utilizar TagGroup en la página de destino.

¿Limitaciones?

  • De momento, entre las transiciones tradicionales soportadas se incluyen las opciones vistas previamente. Proximamente espero añadir alguna opción más (Scale, etc.).
  • Las transiciones de elementos compartidos funcionan con: Label, Image, Button. Próximamente se añadirá soporte a más elementos.
  • Funciona utilizando una NavigationPage. No tiene integración con Shell por ahora.

Animaciones

Llegamos al detalle final del ejemplo. Aunque al navegar a la página de detalles la transición realizada con la imagen que se situará como cabecera conseguirá ya un efecto de fluidez y continuidad elevado, también contamos con una animación del resto del contenido.

Xamarin.Forms cuenta con una API de animaciones completa y sencilla de utilizar. Sin embargo, vamos a conseguir el efecto buscado de forma aún más sencilla directamente desde XAML utilizando Xamanimation.

Para utilizar la librería, comenzamos añadiendo el namespace en la página de detalles:

xmlns:xamanimation="clr-namespace:Xamanimation;assembly=Xamanimation"

A continuación, vamos a crear un Storyboard:

<xamanimation:StoryBoard
     x:Key="ArtItemContentAnimation"
     Target="{x:Reference ArtItemContent}">
     <xamanimation:TranslateToAnimation TranslateY="0" Duration="300"/>
     <xamanimation:FadeInAnimation />
</xamanimation:StoryBoard>

El Storyboard nos permite realizar una animación más compleja, compuesta por otras animaciones. Vamos a hacer una animación de translación hacia arriba además de hacer animar la opacidad del contenido (de 0 a 1).

¿Y cómo se lanza la animación?

Utilizamos un Trigger, para lanzar la animación en el evento Appearing de la página:

<ContentPage.Triggers>
     <EventTrigger Event="Appearing">
          <xamanimation:BeginAnimation 
               Animation="{StaticResource ArtItemContentAnimation}" />
     </EventTrigger>
</ContentPage.Triggers>

El resultado final:

El resultado

¿Qué te parece?

En cuanto al ejemplo, esta disponible en GitHub:

Ver GitHub

Llegamos hasta aquí. Estamos ante un UI Challenge donde el mayor punto de interés recae en las transiciones. Espero que te haya resultado interesante. Pronto más y mejor. Recuerda, cualquier comentario es bienvenida en el artículo!.

Más información

[DotNet 2019] Reto Xamarin

El evento

El próximo 19 de Junio tendrá lugar en Madrid la segunda edición de la DotNet 2019 organizada por Plain Concepts, el evento técnico con tecnologías Microsoft más importante de España.

DotNet 2019

Tengo la suerte de poder participar este año con una sesión con consejos relacionados con el rendimiento en Xamarin.Forms. Con la idea de rendimiento y una entrada para el evento surge el siguiente reto…

El reto

En el siguiente repositorio puedes encontrar un ejemplo Xamarin.Forms haciendo uso de la api de The Movie DB.

¿Puedes encontrar 3 mejoras en rendimiento?

A pesar de usar algunas buenas prácticas, cuentan con una gran variedad de posibles mejoras relacionadas con el rendimiento.

El reto es sencillo. Haz un fork del repositorio, encuentra 3 mejoras en rendimiento y envía una Pull Request. Si eres el primero en enviar Pull Request y con 3 mejoras válidas, ganarás una entrada para la DotNet 2019.

Las reglas

Tan sencillo como:

  • Haz un fork del repositorio.
  • Ejecuta, prueba y piensa.
  • Añade 3 cambios que impacten en el rendimiento.
  • Envía una PR con los cambios.

Tienes hasta el 19 de Mayo para participar. El ganador será el primero que envíe una PR válida (cuente con 3 mejoras de rendimiento).

Sencillo, ¿verdad?.

¿Una pista?

No creo que te haga falta, pero…venga, una pequeña ayuda. Hay posibles mejoras en:

  • Inicio de la App
  • Enlace a datos
  • Uso de Layouts
  • Uso de controles
  • Uso de imágenes
  • Etc

Es posible aplicar 3 mejoras de rendimiento en 5 minutos así que, anímate a participar!.

Más información

[Xamarin.Forms Challenge] My Tasks

Introducción

Según evoluciona de Xamarin.Forms, llegan más y más opciones que simplifican la creación de diferentes elementos de la interfaz de usuario.

En el estado actual de Xamarin.Forms se pueden conseguir aplicaciones nativas de gran escala, con interfaces cuidadas y con alta integración con la plataforma. Hay que tener en cuenta el conjunto de Custom Renderers (código específico en cada plataforma) necesario para lograrlo.

NOTA:La elección entre Xamarin Classic o Xamarin.Forms es importante. Es necesario evaluar la aplicación a desarrollar, el conjunto de características específicas de cada plataforma (que pueden requerir un Custom Renderer), etc. 

En este artículo, vamos a tomar como referencia un diseño de Dribbble (por Anton Aheichanka), que intentaremos replicar con Xamarin.Formspaso a paso.

El diseño

My Tasks

Vamos a intentar replicar la UI del diseño paso a paso en Xamarin.Forms.

Los retos del ejemplo

Vamos a comenzar haciendo un análisis de la interfaz de usuario desglosando los elementos que la componen:

  • Cabecera: La cabecera cuenta con información del perfil de usuario. La imagen del perfil es circular algo que es sencillo de conseguir de diversas formas (FFImageLoadingcon transformaciones, ImageCirclePlugino incluso con SkiaSharp). La otra característica destacada de la cabecera es la imagen de fondo ya que tiene un corte horizontal sencillo pero que hace destacar aun más la cabecera. Entre las opciones que tenemos, una de las más sencillas es utilizar SkiaSharp.
  • El listado: El listado cuenta con una cabecera sencilla pero elegante, fácil de conseguir con la propiedad Header del ListView; elementos que se pueden conseguir definiendo una celda personalizada. En la celda, en caso de reuniones se muestran los participantes. Ahora gracias a BindableLayout es algo sencillo.
  • El menu de filtro: La característica principal de la vista. Una de mis APIs favoritas en Xamarin.Forms es la de animaciones. Sencilla pero ofrece una libertas muy alta. En este caso, podemos replicarlo usando una ContentView con imágenes en el interior y el efecto de apertura y cierre del menu lo conseguimos a base de animaciones (de escala, opacidad, etc.).

Imagen con corte horizontal

¿Cómo conseguimos la imagen con corte horizontal?

SkiaSharpsuele ser una opción ideal para opciones de dibujado. En este caso, nos vendría genial directamente dibujar la imagen pero recortando una pequeña parte (triangulo) de la parte inferior. SkiaSharp permite cargar imágenes además de tener una enorme variedad de posibilidades al tratar la misma. aplicar diferentes transformaciones, efectos, etc. Podemos hacer un recorte con trazado (un path) de una imagen.

Tras añadir los paquetes de SkiaSharp.Views.Formsa la solución, creamos un nuevo control que herede de SKCanvasView.

Comenzamos definiendo el trazado que usaremos para recortar la imagen:

SKPath Path = SKPath.ParseSvgPathData("m 0 0 l 400 0 l 0 300 l -400 -50");

Usamos el método ClipPathpara hacer el recorte:

canvas.ClipPath(Path);

Para dibujar la imagen usamos SKBitmap que pintaremos con el método DrawBitmap:

canvas.DrawBitmap(_bitmap, info.Rect);

Sencillo, ¿verdad?

Listado

Llegamos al listado. No tiene nada especialmente complejo, pero vamos a ir desglosando cada bloque. Comenzamos por la cabecera. Nos apoyamos en la propiedad Header del ListView para definir la misma:

<ListView.Header>
     <templates:TaskHeaderTemplate />
</ListView.Header>

Donde TaskHeaderTemplatees un ContentViewcon la definición de la cabecera.

Cada elemento del listado es definido en el ItemTemplatedel listado:

<ListView.ItemTemplate>
     <DataTemplate>
          <ViewCell>
               <templates:TaskItemTemplate />
          </ViewCell>
     </DataTemplate>
</ListView.ItemTemplate>

En la definición de cada elemento del listado tenemos una peculiaridad. En caso de reunión, mostramos las personas que asisten. Para ello, hacemos uso de BindableLayoutintroducido en Xamarin.Forms 3.5:

<StackLayout
     Orientation="Horizontal"
     BindableLayout.ItemsSource="{Binding People}">
     <BindableLayout.ItemTemplate>
          <DataTemplate>
               <Grid>
                    <imageCircle:CircleImage 
                    Source="{Binding Photo}"
                    Aspect="AspectFit"
                    Style="{StaticResource PhotoStyle}"/>
               </Grid>
          </DataTemplate>
     </BindableLayout.ItemTemplate>
</StackLayout>

Pero nos sigue quedando una peculiaridad del ejemplo en el listado…

Animando cada elemento del listado

Cada vez que se añaden o quitan elementos al listado, se introducen con una breve pero efectiva animación de Fade In y translación hacia arriba.

¿Cómo lo conseguimos?

Vamos a crear una ViewCellpersonalizada. Para ellos creamos una clase que here de ViewCell y al añadir un elemento hijo:

protected override void OnChildAdded(Element child)
{
     base.OnChildAdded(child);

     uint duration = 750;

     var animation = new Animation();

     animation.WithConcurrent((f) => TaskItemTemplate.Opacity = f, 0, 1, Easing.CubicOut);

     animation.WithConcurrent(
     (f) => TaskItemTemplate.TranslationY = f,
     TaskItemTemplate.TranslationY + 50, 0,
     Easing.CubicOut, 0, 1);

     TaskItemTemplate.Animate("FadeIn", animation, 16, Convert.ToUInt32(duration));
}

La definición del ItemTemplate del ListView debe cambiar a algo como:

<ListView.ItemTemplate>
     <DataTemplate>
          <cells:TaskItemViewCell />
     </DataTemplate>
</ListView.ItemTemplate>

Voila!

Filtro circular

Y llegamos a la parte más atractiva del ejemplo.

¿Cómo conseguirla de forma sencilla?

Vamos a crear un ContentViewque contendrá primero la imagen del menu cerrado. Por otro lado, la imagen para cerrar el menu y el fondo expandido además de claro, una imagen por cada elemento del menu.

Haremos uso de GestureRecognizerspara capturar las pulsaciones en el menu o cada elemento del menú. Al pulsar haremos dos acciones.

Por un lado, lanzaremos un comando definido en el control:

public static readonly BindableProperty SelectedCommandProperty =
     BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(FilterMenu), null);

public ICommand SelectedCommand
{
     get { return (ICommand)GetValue(SelectedCommandProperty); }
     set { SetValue(SelectedCommandProperty, value); }
}

Y por otro lado, haremos uso de animaciones!. Veamos por ejemplo, que hacemos para abrir el menu:

await InnerButtonMenu.RotateTo(360, _animationDelay);
await InnerButtonMenu.FadeTo(0, _animationDelay);
await InnerButtonClose.RotateTo(360, _animationDelay);
await InnerButtonClose.FadeTo(1, _animationDelay);
await OuterCircle.ScaleTo(3.5, 100, Easing.Linear);
await N.FadeTo(1, speed);
await NW.FadeTo(1, speed);
await SW.FadeTo(1, speed);
await S.FadeTo(1, speed);

Ocultamos con una rotación el botón (imagen) para abrir el menu. a continuación mostramos el botón de cerrar y escalamos (importante!) el area del menu. Por último, cambiamos la opacidad de cada elemento del menu.

Sencillo, pero realmente espectacular y efectivo.

Esta idea de menu esta basada en un gran ejemplo de Alan Beechque Ricardo Vasquezha elaborado más para tener un control.

El resultado conseguido:

El resultado

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Hasta aquí el desglose del ejemplo. Lo terminamos sin Custom Renderers o efectos, haciendo uso de Xamarin.Forms y sus APIs para tareas complejas como el menú de filtro o el listado y apoyándonos en SkiaSharp para algunas tareas.

Cualquier duda o comentario es bienvenido en los comentarios!

Más información

[Xamarin.Forms] Utilizando Bindable Layouts

Introducción

En Xamarin.Forms tenemos un tipo especial de View llamada Layout. Un Layout es un contenedor para otros elementos permitiendo ayudar a posicionar y gestionar el tamaño de los elementos que contiene. En Xamarin.Forms contamos con una gran variedad de Layouts:

Layouts en Xamarin.Forms

Los más utilizados son el StackLayout y el Grid, y suele ser habitual hacer una composición de varios así como utilizarlos para crear controles, etc. Por ejemplo, en ocasiones se utiliza la combinación de ScrollView y StackLayout junto con ContentViews para crear un pequeño listado de elementos horizontal.

Bindable Layout

Con la llegada de Xamarin.Forms 3.5 pre2 nos llega Bindable Layout. En toda clase derivada de Layout<T>, contamos ahora con las siguientes propiedades:

  • ItemsSource: De tipo IEnumerable, soporta el enlace de una colección de datos.
  • ItemTemplate: De tipo DataTemplate, permitirá definir la apariencia visual de cada elemento.
  • ItemTemplateSelector: De tipo ItemTemplateSelector, permite poder elegir entre diferentes templates para cada elemento en base a ciertas condiciones.

Las propiedades resultan familiares conociendo otros controles en Xamarin.Forms como el ListView.

¿Recuerdas el ejemplo que hemos mencionado de listado horizontal?. Utilizando Bindable Layout todo se simplifica.

Uso básico

De la interfaz que estamos replicando, el caso más sencillo es el listado de amigos.

<StackLayout
     Orientation="Horizontal"
     BindableLayout.ItemsSource="{Binding Profile.Friends}">
     <BindableLayout.ItemTemplate>
          <DataTemplate>
          <Grid>
               <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
               </Grid.RowDefinitions>
                    <imageCircle:CircleImage 
                         Grid.Row="0"
                         Source="{Binding Picture}"
                         Aspect="AspectFit"
                         Style="{StaticResource FriendImageStyle}"/>
                    <Label 
                    Grid.Row="1"
                         Text="{Binding Name}"
                         Style="{StaticResource FriendNameStyle}"/>
               </Grid>
          </DataTemplate>
     </BindableLayout.ItemTemplate>
</StackLayout>

El resultado:

Bindable StackLayout

Sencillo, ¿verdad?.

Utilizando Bindable Layout con DataTemplateSelector

Pasamos a una necesidad más compleja, la galería. En la galería vamos a necesitar mostrar elementos con diferente tamaño.

¿Qué podemos hacer?

Vamos a analizar que necesitamos:

  • Los elementos hacen wrapping.
  • Los elementos se organizan de izquierda a derecha.
  • Hay imágenes de diferente tamaño.

FlexLayout nos permitirá ambas opciones. Definimos el control:

<FlexLayout
     Style="{StaticResource GalleryStyle}" />

Utilizamos un estilo para habilitar el Wrapping, etc. A continuación, vamos a hacer uso de Bindable Layout para evitar definir N imágenes dentro del Layout.

<FlexLayout
     BindableLayout.ItemsSource="{Binding Profile.Gallery}"
     BindableLayout.ItemTemplateSelector="{StaticResource GalleryItemTemplateSelector}"
     Style="{StaticResource GalleryStyle}" />

Al contar con la necesidad de tener imágenes de diferente tamaño en la galería, vamos a utilizar la propiedad ItemTemplateSelector para utilizar diferentes plantillas:

<styles:GalleryItemTemplateSelector x:Key="GalleryItemTemplateSelector">
     <styles:GalleryItemTemplateSelector.MediumGalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}"
                    Aspect="AspectFill"
                    StyleClass="photo, medium"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.MediumGalleryItemTemplate>
     <styles:GalleryItemTemplateSelector.BigGalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}"
                    Aspect="AspectFill"
                    StyleClass="photo, big"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.BigGalleryItemTemplate>
     <styles:GalleryItemTemplateSelector.GalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}" 
                    Aspect="AspectFill"
                    StyleClass="photo"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.GalleryItemTemplate>
</styles:GalleryItemTemplateSelector>

El resultado:

Bindable FlexLayout

Veamos el resultado completo:

El resultado

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

¿Qué te parece Layout Bindable?. Recuerda, puedes dejar cualquier duda o comentario en la entrada!

Más información

[Preview] Primer vistazo a Xamarin.Forms CollectionView

Introducción

Como parte de las novedades que llegan con Xamarin.Forms 4.0 se encuentra el nuevo control CollectionView.

Xamarin.Forms CollectionView

CollectionView llega con el objetivo de mejorar lo ofrecido por el control ListView hasta ahora:

  • Facilitar más opciones como listados horizontales o Grids.
  • Cubrir opciones muy solicitadas (vista para cuando no hay contenido, etc.).
  • Mejorar rendimiento.
  • Etc.

Primeros pasos

Para habilitar CollectionView es necesario utilizar un flag antes de inicializar Xamarin.Forms (recuerda, estamos ante una preview).

global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");

Layout básico

Podemos conseguir el mismo Layout de un ListView de forma sencilla. Como ventaja, con CollectionView no es necesario utilizar celdas, es decir, no usaremos ViewCell. Esto tiene un impacto en el rendimiento, sobretodo en Android, pero manteniendo la estructura y Layout del ListView.

<CollectionView 
     ItemsSource="{Binding Monkeys}">
     <CollectionView.ItemTemplate>
          <DataTemplate>
               <Grid 
                    HeightRequest="48">
                    <Label 
                         Text="{Binding Name}"
                         FontSize="18"
                         VerticalOptions="Center"/>
               </Grid>
          </DataTemplate>
     </CollectionView.ItemTemplate>
</CollectionView>

El resultado:

Layout básico

Fíjate que usamos un DataTemplate sin necesidad de ViewCell!.

Listas horizontales

Por defecto, el CollectionView utilizar un layout lineal. Esto quiere decir que se pueden hacer listas verticales pero…también horizontales!.

El control CollectionView cuenta con la propiedad ItemsLayout. Podemos establecer esta propiedad a una nueva instancia de GridItemsLayout que cuenta con una propiedad Orientation para definir la orientación.

<CollectionView.ItemsLayout>
     <GridItemsLayout
          Orientation="Horizontal" />
</CollectionView.ItemsLayout>

El resultado:

Listas horizontales

Carousel

Algo similar pero más complejo, un Carousel. Contar con un elemento scrollable pero navegando de elemento en elemento. Contamos con un control llamado CarouselView, un control nuevo basado en CollectionView, que podemos utilizar para conseguir el formato clásico de “carta” y paso de elemento a elemento:

<CarouselView 
     ItemsSource="{Binding Monkeys}">
     <CarouselView.ItemsLayout>
          <GridItemsLayout
               Orientation="Horizontal" 
               SnapPointsAlignment="Center" 
               SnapPointsType="Mandatory"/>
     </CarouselView.ItemsLayout>
</CarouselView>

El resultado:

Carousel

Una de las características más interesantes que tenemos disponible es la posibilidad de controlar el comportamiento y alineación de cada elemento al hacer el desplazamiento. Lo conseguimos con las propiedades SnapPointsType y SnapPointsAlignment.

Grid

Por defecto, CollectionView utiliza un layout lineal. Es decir, por defecto podemos hacer listas verticales u horizontales. Como ya vimos previamente, con la propiedad ItemsLayout podemos modificar el comportamiento del Layout.

<CollectionView.ItemsLayout>
     <GridItemsLayout
          Orientation="Vertical"
          Span="2"/>
</CollectionView.ItemsLayout>

Utilizando GridItemsLayout podemos controlar la orientación con la propiedad Orientation y con la propiedad Span el número de elementos por fila o columna.

Grid Layout

Vista cuando no hay contenido

¿Qué ocurre cuando ItemsSource no tiene elementos?. Probablemente, hasta ahora con el ListView has jugado con paneles y visibilidad para dar feedback al usuario ante esta situación. CollectionView viene a mejorar esto. Podemos utilizar la propiedad EmptyView para mostrar cualquier contenido en caso de tener elementos.

<CollectionView 
     ItemsSource="{Binding Monkeys}">
     <CollectionView.EmptyView>
          <Grid>
          <Label 
               Text="No items"
               HorizontalOptions="Center"
               VerticalOptions="Center"/>
          </Grid>
     </CollectionView.EmptyView>
</CollectionView>

El resultado:

Sin contenido

Sencillo, ¿verdad?.

Tienes el ejemplo disponible en GitHub:

Ver GitHub¿Qué te parece?, ¿qué te resulta más interesante?. Recuerda, puedes dejar comentarios en la entrada!.

Más información

[Preview] Primer vistazo a Xamarin.Forms Visual

Introducción

A la hora de desarrollar aplicaciones multiplataforma, buscamos llegar a diferentes plataformas cada una de ellas con sus propias guías de estilo, controles e idiosincrasia. Sin embargo, en ocasiones como desarrolladores móviles buscamos conseguir el mismo aspecto. Con Xamarin.Forms, a pesar de contar con una capa de abstracción en la capa de UI permitiendo definir la interfaz una única vez, creamos aplicaciones nativas. Es decir, utilizando Xamarin.Forms utilizamos los controles nativos de cada plataforma. Para conseguir un mismo aspecto necesitamos utilizar Custom Renderers o efectos en ocasiones.

Xamarin.Forms Visual

Con Xamarin.Forms 4.0-pre1 nos llega una nueva forma de indicar una forma de renderizar los controles nativos con Visual.

Cuando utilizamos Visual, se utiliza el renderizado personalizado en cada plataforma en lugar del renderizado predeterminado.

NOTA: Utilizando Visual seguimos utilizando controles 100% nativos.

Para establecer el uso de Visual, utilizaremos la propiedad Visual:

<ContentPage 
     Visual="Material">

</ContentPage>

La propiedad Visual esta disponible en la clase VisualElement. Cualquier elemento hijo de otro heredará el valor de la propiedad y modificará su forma de renderizar. Por este motivo, si establecemos Visual a nivel de ContentPage aseguramos que cualquier elemento de la página utilizará el nuevo sistema de renderizado.

NOTA: El valor de la propiedad Visual puede cambiar en tiempo de ejecución.

Nos llega esta funcionalidad en modo Preview con la apariencia basada en Material Design. Actualmente, en la versión 4.0-pre1 contamos con Material Design en Android e iOS para los siguientes controles:

  • Button
  • Entry
  • Frame
  • ProgressBar

Para utilizar Visual, por ahora (recuerda, estamos ante una Preview) es necesario añadir la siguiente línea:

Forms.SetFlags("Visual_Experimental");

Antes de llamar a Forms.Init. Además, en iOS, es necesario añadir el paquete NuGet Xamarin.iOS.MaterialComponents.

NOTA: Visual requiere API 29 para funcionar en Android.

Veamos un ejemplo:

<Grid
     BackgroundColor="DarkGray">
     <Frame 
          Style="{StaticResource SignInFrameStyle}">
          <StackLayout 
               Style="{StaticResource SignInPanelStyle}">
               <Label 
                    Text="Sign in"
                    Style="{StaticResource SignInTitleStyle}" />
               <Entry 
                    Placeholder="Username" />
               <Entry 
                    IsPassword="True"
                    Placeholder="Password" />
               <Button 
                    Text="Sign in" 
                    Style="{StaticResource SignInButtontyle}"/>
          </StackLayout>
     </Frame>
</Grid>

El resultado:

Visual

Tienes el ejemplo disponible en GitHub:

Ver GitHub

Más información

[Material] Monkey Conf 2018

El evento

En España tenemos una comunidad .NET activa y diversa. Gracias a ello tenemos eventos anuales de gran calidad relacionadas con Azure, SQL Server e incluso AI. Sin embargo, a pesar de contar con una enorme variedad de desarrolladores Xamarin realizando grandes cosas, nos faltaba un evento donde reunirnos todos. Para solventar este problema, nace Monkey Conf 2018.

Con una enorme facilidad, hablando con compañeros y amigos el evento empezó a tomar forma muy rápidamente. Muchos quisieron patrocinar el evento (gracias a ellos pudimos tener desayuno, almuerzo, camisetas o regalar licencias), otros querían participar con sesiones, e incluso algunos se ofrecieron para ayudar con la organización, etc.

Gracias a todos ellos, el pasado 01 de Diciembre, celebramos la Monkey Conf 2018. A continuación, una pequeña galería del evento:

Fue un día lleno de sesiones técnicas de calidad. Es increíble ver sesiones donde se dan consejos de distribución y venta de apps basadas en la experiencia real con consejos de arquitectura de código. Esto demuestra el nivel y madurez de la comunidad Xamarin. Desde la recepción hasta el final, donde no podía faltar “el preguntón” (gracias a MFractor, LiveXaml y Steema por facilitarnos licencias) el día fluyo de forma natural, sin ningun problema de ningún tipo. Muchas gracias a sponsors, asistentes y ponentes por ello!.

Sponsors, gracias!

Quiero destacar un momento, inesperado y emotivo. Entre los ponentes decidieron darme una sorpresa y me regalaron un teclado Corsair mecánico que ya estoy utilizando. Como se suele decir, chicos, no teníais porque, pero muy agradecido!.

Muchas gracias!

El material

Vamos al material. Participé en el evento con una sesión acerca de Xamarin.Forms Shell.

Aprendimos en que consiste, vimos como funciona Visual para conseguir la misma apariencia en Android e iOS y también conocimos CollectionView.

Por la tarde participé en un taller de desarrollo de aplicaciones Xamarin.

Realizamos una divertida aplicación con Xamarin.Forms y Custom Vision para determinar si una foto tomada desde la aplicación, es un HotDot o no (si, la idea viene de la serie Silicon Valley de HBO).

En cuanto al material (ejemplos, demos), se esta recopilando todo en un repositorio disponible en GitHub:

Ver GitHub

Más información

[Material] Analizando interfaces de usuario avanzadas con Xamarin.Forms

El evento

El pasado 26 de Septiembre, teníamos en SVQXDG un divertido evento donde abriendo debate e intercambiando ideas algunos de los ejemplos revisamos opciones disponibles para conseguir interfaces atractivas con Xamarin.Forms. Vimos opciones como efectos, Custom Renderers, SkiaSharp, VisualStateManager, etc.

El material

A continuación puedes encontrar la presentación utilizada en el evento:

En cuanto a ejemplos, revisamos muchos ejemplos revisando UI y opciones en cada uno de ellos.

My Trip Countdown

Sencillo contador atrás hacia el momento de una fecha (viaje).

My Trip Countdown

Las claves:

  • Uso de SkiaSharp para crear progreso circularcon degradado.
  • Gestión de imágenes con efectos (circular).
  • Botón con degradado.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Pulse Music

Interfaz de un reproductor de música.

Pulse Music

Las claves:

  • Uso de SkiaSharp para crear progreso circular.
  • Animaciones infinitas.
  • Gestión de imágenes con efectos (circular).

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Walkthrough

Creación de un Walkthrough con diferentes pasos animados.

Walkthrough

Las claves:

  • Uso de Carousel.
  • Animaciones con Lottie.
  • API de animaciones de Xamarin.Forms.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Netflix

Ejemplo donde se replica la interfaz básica de Netflix.

Vista principal en Android

La claves de este ejemplo:

  • Navegación personalizada (logo, transparencias, etc.).
  • Listados horizontales.
  • Parallax.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Movies

El último ejemplo que revisamos. Aplicación utilizando la API de TheMovieDB.

Movies

La claves de este ejemplo:

  • Crear aplicaciones para Linux y WPF utilizando Xamarin.Forms.
  • Personalizar estilos para Linux y WPF.
  • Aplicar temas GTK.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Más información