[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 UI Challenge] TimelinePulse

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.Forms paso a paso.

Timeline Profile

TimelinePulse

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:

  • Barra de navegación: Muestra el título centrado (y con una fuente específica) además de la imagen del perfil del usuario para permitir navegar rápidamente al perfil. Gracias a la propiedad TitleView de la NavigationPage, podemos añadir contenido personalizado y conseguir el resultado facilmente.
  • Cabecera: La cabecera muestra información relacionada con la fecha. Sin embargo, No hay nada complejo en la misma. Aplicar una imagen de fondo, y utilizar un Layout (por ejemplo, un Grid) para posicionar la información de la fecha con textos utilizando una fuente específica.
  • El botón para añadir: Aquí es donde vamos a tener la parte más compleja del ejemplo. ¿Por qué?. Queremos aplicar un efecto de pulso para llamar la atención del usuario. Tenemos varias formas de conseguir el resultado. Entre ellas contamos con el uso las APIs de animación de Xamarin.Forms junto con el uso de imágenes; SkiaSharp o bien Custom Renderers.
  • El listado: El listado cuenta con 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.

NOTA: En este ejemplo nos hemos centrado en la vista con el timeline, por ese motivo el ejemplo no cuenta con el menu lateral deslizante u otras opciones.

Imágenes circulares

Tenemos muchas opciones para crear imágenes circulares. Entre las opciones disponibles destacan FFImageloading e ImageCirclePlugin. Sin embargo, no son las únicas opciones. A continuación, vamos a crear un pequeño control para tener imágenes circulares usando SkiaSharp.

Tras añadir SkiaSharp.Views.Forms a cada proyecto de la solución, creamos un nuevo control derivado de SKCanvasView:

public class CircularImage : SKCanvasView
{

}

Vamos a necesitar una propiedad para definir la imagen a utilizar:

public static readonly BindableProperty EmbeddedImageNameProperty =
     BindableProperty.Create(nameof(EmbeddedImageName), typeof(string), typeof(CircularImage), "", propertyChanged: OnPropertyChanged);

public string EmbeddedImageName
{
     get { return (string)GetValue(EmbeddedImageNameProperty); }
     set { SetValue(EmbeddedImageNameProperty, value); }
}

Lo que vamos a realizar, es aplicarle un Path a la imagen, recortando en la forma deseada, circular:

SKPath CircularPath = SKPath.ParseSvgPathData("M -1,0 A 1,1 0 1 1 1,0 M -1,0 A 1,1 0 1 0 1,0");

La clave es utilizar el método ClipPath junto con DrawBitmap:

canvas.Clear();

CircularPath.GetBounds(out SKRect bounds);
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.Scale(0.98f * info.Height / bounds.Height);
canvas.Translate(-bounds.MidX, -bounds.MidY);
canvas.ClipPath(CircularPath);
canvas.ResetMatrix();

if (_resourceBitmap != null)
{
     canvas.DrawBitmap(_resourceBitmap, info.Rect);
}

Esto fue sencillo, ¿verdad?. Continuamos.

La barra de navegación

Pasamos a ver la barra de navegación. Utilizamos una NavigationPage donde con la propiedad BarBackgroundColor definimos de forma sencilla el color de fondo. ¿Y el contenido?.

Usamos la propiedad TitleView para definir el contenido personalizado:

<NavigationPage.TitleView>
     <Grid>
          <Label 
               Text="Timeline" 
               Style="{StaticResource BarTitleStyle}"/>
          <Grid
               HorizontalOptions="End"
               Margin="6, 0">
               <controls:CircularImage 
                    EmbeddedImageName="TimelinePulse.Resources.face1.jpg"/>
          </Grid>
     </Grid>
</NavigationPage.TitleView>

Listado

Llegamos al listado. No tiene nada especialmente complejo, pero vamos a ir desglosando cada bloque.

Cada elemento del listado es definido en el ItemTemplate del 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 BindableLayout introducido en Xamarin.Forms 3.5:

<StackLayout
     Orientation="Horizontal"
     BindableLayout.ItemsSource="{Binding People}">
     <BindableLayout.ItemTemplate>
          <DataTemplate>
               <Grid>
                    <controls:CircularImage
                         EmbeddedImageName="{Binding Photo}"
                         Style="{StaticResource PhotoStyle}"/>
               </Grid>
          </DataTemplate>
     </BindableLayout.ItemTemplate>
</StackLayout>

Botón con animación

Y llegamos a quizás el «eje» del ejemplo. Sin duda, la parte más detacada, el botón con la animación.

¿Cómo lo conseguimos?

Tenemos diferentes opciones, pero al igual que antes con las imágenes circulares, vamos a usar SkiaSharp.

Comenzamos creando un nuevo control, una nueva clase que herede de SKCanvasView:

public class PulseButton : SKCanvasView
{

}

Definimos algunas propiedades como:

  • EmbeddedImageName: Para poder establecer la imagen del botón.
  • PulseColor: Para definir el color de fondo del botón (circulo).
  • PulseSpeed: Ya que la clave es la animación, mejor tener control sobre la misma.

NOTA: Podríamos definir otras propiedades interesantes como IsAnimating para parar o lanzar la animación, Command para ejecutar una acción, etc. Ten en cuenta que es un ejemplo destinado a cubrir la UI, no una App real.

Para definir el botón, dibujaremos un círculo con el método DrawCircle y en caso de establecer una imagen vía propiedad (creada en el control de forma similar a como hicimos en el control CircularImage), la dibujaremos usando el método DrawBitmap.

canvas.Clear();

SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);

paint.Color = new SKColor(R, G, B);
canvas.DrawCircle(center.X, center.Y, 85, paint);

if (_resourceBitmap != null)
     canvas.DrawBitmap(_resourceBitmap, center.X - _resourceBitmap.Width / 2, center.Y - _resourceBitmap.Height / 2);

Hasta aquí todo muy sencillo. Unas propiedades básicas y un dibujado de un circula e imagen. Con esto tenemos el botón básico, pero…¿y la animación Pulse?.

Vamos a utilizar un StopWatcher para obtener un valor que irá cambiando en base al número de milisegundos que han pasado:

_time = (float)(_stopwatch.Elapsed.TotalMilliseconds % speed / speed);

NOTA: Cada X tiempo debemos refrescar la UI para que el efecto de la animación sea correcto. Esto lo conseguimos con el método InvalidateSurface.

Lo que queda es simple, debemos dibujar otro circulo de igual forma que el anterior pero con un par de detalles:

  • Será mayor a mayor con el paso del tiempo.
  • La opacidad será menor con el paso del tiempo.
SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
float radius = info.Width / 2 * _time;

paint.Color = new SKColor(R, G, B, (byte)(255 * (1 - _time)));
paint.Style = SKPaintStyle.Fill;
canvas.DrawCircle(center.X, center.Y, radius, paint);

Fíjate en el código anterior. Usamos la variable _time (recuerda el StopWatch), para ajustar la opacidad y el radio.

El resultado final:

El resultado

Llegamos hasta aquí. Estamos ante un UI Challenge no muy complejo pero con detalles interesantes.  Espero que te haya resultado interesante. El próximo será mucho más complejo…

Recuerda, cualquier comentario es bienvenida en el artículo!.

Más información

Novedades en Xamarin.Forms 3.6

Introducción

Versión tras versión recibimos novedades en Xamarin.Forms. En la última versión estable (3.6) hemos recibimos múltiples novedades de peso (donde brilla con luz propia Visual). ¿Y si las repasamos todas?.

Novedades

A continuación, vamos a realizar un repaso de todas las principales novedades introducidas en esta versión.

Visual

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.

Con Visual nos llega una nueva forma de indicar una forma de renderizar los controles nativos.

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.

Además, se incluye la posibilidad de crear Custom Renderer para Visual.

ItemsSource e ItemTemplate en mapas

En esta versión se añaden dos nuevas propiedades el control de tipo mapa:

  • ItemsSource: Especifica la colección de tipo IEnumerable de elementos a mostrar.
  • ItemTemplate: DataTemplate a utilizar en cada elemento de la colección.

Un ejemplo:

<map:Map
     ItemsSource="{Binding Places}">
          <map:Map.ItemTemplate>
          <DataTemplate>
               <map:Pin 
                    Position="{Binding Position}"
                    Address="{Binding Address}"
                    Label="{Binding Description}" />
          </DataTemplate>
     </map:Map.ItemTemplate>
</map:Map>

Y el resultado:

ItemsSource e ItemTemplate en mapas!

FontImageSource

Se añade un nuevo tipo ed imagen, la clase FontImageSource derivada de ImageSource. Permite mostrar iconos que provienen de fuentes.

Cuenta con las siguientes propiedades:

  • Glyph: Valor de tipo cadena que especifica el caracter a utilizar de la fuente.
  • Color: Color a usar en el Glyph.
  • FontFamily: La fuente a utilizar.
  • Size: Valor de tipo double que especifica el tamaño a utilizar al renderizar el icono. El valor por defecto es 30.

Veamos un ejemplo:

<Image
     BackgroundColor="Gray">
     <Image.Source>
          <FontImageSource 
               Glyph="{Binding Glyph}"
               FontFamily="{OnPlatform iOS=Ionicons, Android=ionicons.ttf#}"
               Size="44"/>
     </Image.Source>
</Image>

Y el resultado:

FontImageSource

 

ReadOnly Entry

Una opción muy solicitada era la posibilidad de tener Entry de solo lectura. Se añade la propiedad IsReadOnly.

<Entry 
     Text="Content..."
     IsReadOnly="true"/>

A diferencia de IsEnabled, esta nueva propiedad no modifica el aspecto visual del control.

Otras novedades

En esta versión se han incluidos otras novedades también interesantes como:

Más información

[Material] Novedades en Xamarin.Forms 4: Shell, CollectionView y más!

El evento

El pasado Jueves 11, celebramos un nuevo evento en SVQXDG (grupo de desarrolladores de Xamarin en Sevilla) donde repasamos todas las últimas novedades de Xamarin.Forms.

Repasando novedades de Xamarin.Forms

El material

A continación, vamos a repasar todo el material (presentación y ejemplos) que vimos en la presentación.

Novedades de Xamarin.Forms 3.5

Comenzamos el evento viendo las últimas novedades en las versiones estables, empezando por la versión 3.5. Vimos:

  • BindableLayout
  • ScrollBarVisibility
  • SwitchCell OnColor
  • Novedades en accesibilidad
  • Otras novedades

En cuanto al ejemplo, esta disponible en GitHub:

Ver GitHub

Novedades en Xamarin.Forms 3.6

Continuamos viendo las novedades de la última versión estable de Xamarin.Forms a la hora de escribir este artículo, la versión 3.6. Novedades:

  • Visual.
  • ItemsSource e ItemTemplate en mapas.
  • FontImageSource.
  • Otras novedades.

En cuanto al ejemplo, esta disponible en GitHub:

Ver GitHub

Visual

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.

Con Visual nos llega una nueva forma de indicar una forma de renderizar los controles nativos.

Hicimos un repaso como usar y que ofrece Visual. Espero que en próximos eventos veamos como crear renderers personalizados con Visual y otras opciones.

CollectionView

Continuamos con más novedades!. Llegaba el momento de hablar de CollectionView creando listados, listados horizontales, diferentes layouts con columnas, etc.

En cuanto al ejemplo, esta disponible en GitHub:

Ver GitHub

Shell

Llegamos al plato fuerte del evento, y la novedad principal con Xamarin.Forms 4, Shell. Vimos:

  • Introducción a Shell.
  • ShellItem, ShellSection y ShellContent.
  • Nuevas opciones al navegar.
  • Crear Flyouts.
  • Barras de búsqueda.
  • Otras opciones (ocultar tabs o nav, etc.).

El ejemplo:

Ver GitHub

Otras novedades

Para terminar el evento, vimos novedades de terceros. En concreto, repasamos Aurora Controls y Grial UI Kit 3.

Como de costumbre, un placer compartir momentos en comunidad. Muchas gracias a todos los asistentes, nos vemos en la próxima!. Pero…un momento. Me gustaría terminar recordando que la comunidad es de todos. Si te apetece hablar de tecnologías .NET o Xamarin, tan solo avísame!.

Más información

[VideoBlog] Un vistazo a Aurora Controls

Introducción

La evolución de Xamarin.Forms es constante. Cada poco tiempo recibimos novedades en forma de nuevos controles (CollectionView o ImageButton por ejemplo), nuevas propiedades, Platform Specifics, etc. con el objetivo de simplificar la creación y personalización de interfaces de usuario.

De igual forma, la comunidad y empresas terceras cada vez lanzan plugins, controles y herramientas de más calidad. Recientemente, recibimos un nuevo paquete de controles, efectos, extensiones, gráficas, etc. llamado Aurora Controls.

Aurora Controls

Aurora Controls ofrece una variedad de controles, extensiones, efectos, gráficas, controles de carga y varios helpers con el objetivo de cubrir necesidades habituales a la hora de desarrollar interfaces de usuario en Xamarin.Forms (degradados, sombras, capturar datos de diferente tipo, etc.).

Una de las características más destacable de una gran parte de los controles es el uso de SkiaSharp para realizar el dibujado de los mismos. Tenéis el código fuente del ejemplo utilizado disponible en GitHub:

Ver GitHubRecordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

Más información

[SVQXDG] Nuevo evento: Un repaso a las últimas novedades en Xamarin.Forms

El evento

Si repasamos la lista de grandes novedades de Xamarin.Forms de los últimos meses encontramos una cantidad elevada de cambios. Hablamos de Shell, Visual, BindableLayout, Bindable Maps, etc que sumado a muchos pequeños detalles (FontIconSource, Read only Entry, etc.) nos brinda nuevas posibilidades.

Xamarin.Forms

¿Y si las recopilamos y vemos todas en un evento?.

El lugar

El evento se celebrará en la ETS de Ingeniería Informática. Dirección detallada:

E.T.S. Ingeniería Informática – Universidad de Sevilla, Aula por confirmar
Av. Reina Mercedes s/n
Sevilla Se 41012

La fecha

Será el próximo Jueves, 11 de Abril de 20:00h a 21:00h (GMT+1).

¿Te apuntas?

Más información

[VS4Mac] Lottie Player, nuevo addin para previsualizar animaciones Lottie

Introducción

¿Te imaginas tomar una animación creada por un diseñador y poder utilizarla?.

Lottiees una librería de animaciones creada por Airbnb para iOS y Android que se encarga de tomar animaciones de After Effect exportadas en JSON y renderizarla utilizando APIs de animación nativa en cada plataforma.

Lottie

Las animaciones pueden ser extremadamente complejas pero al final, trabajamos con archivos de imagen y JSONs lo que se traduce en un requisito pequeño en tamaño otorgando unas posibilidades altas. Las animaciones se pueden reproducir, pausar, detener, jugar con la velocidad o cambiar la escala.

Lottie Player

Usar animaciones de Lottie y acabar lanzando la App en depuración o usando herramientas externas para ver el resultado no es lo idóneo, ¿verdad?. Lottie Playeres un addin para Visual Studio para macOS que permite previsualizar (e interactuar) con la animación directamente desde el IDE.

¿Cómo instalar?

Para instalar el addin, en Visual Studio para macOS, accedemos al menu principal y seleccionamos Extensions…

Buscamos por «Lottie Player»:

Instalar Lottie Player…

Y pulsamos Install…

¿Qué aporta?

Podremos hacer clic derecho sobre un archivo de animación Lottie (recuerda, formato Json) y acceder a una nueva opción, Preview In Lottie Player…

Lottie Player

Seleccionando la opción, previsualizaremos la animación en bucle además de:

  • Poder pausar y reanudar la animación en cualquier momento.
  • Si pausamos la animación, podremos movernos hacia cualquier frame de la animación.

Veamos el addin en funcionamiento:

Preview in Lottie Player

Lo próximo

La versión actual aporta la funcionalidad básica pero hay una gran cantidad de opciones posibles para futuras versiones:

  • Controlar la velocidad de la animación.
  • Controlar si se reproduce o no en bucle.
  • Poder cambiar el fondo de la animación.
  • Etc.

Puedes encontrar el código del addin en GitHub:

Ver GitHub

¿Qué te parece el addin?. Recuerda, puedes dejar un comentario directamente en la entrada!

Más información