[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

Anuncios

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

[CartujaDotNet] Nuevo evento: Extender Visual Studio para macOS

El evento

Si vienes usando Visual Studio probablemente sepas acerca de la posibilidad de extensibilidad. Crear extensiones para cubrir o mejorar cierta funcionalidad (plantilla de proyectos, nueva herramienta, etc.). ¿Sabías que es también posible en Visual Studio para macOS?.

En esta sesión, conoceremos como extender Visual Studio para macOS; como depurar una extensión así como ver todos los puntos principales de extensión todo a base de ejemplos.

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 19:00h a 20: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?.

Lottie es 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 Player es 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

[VS4Mac] Git History integrado como addin

Introducción

A la hora de trabajar con un proyecto en Git, Visual Studio para macOS cuenta con soporte integrado. Sin embargo, recientemente probé git-history. Sin duda, una forma intuitiva y muy interesante para ver le historial de cambios en un archivo. Así que, ¿por qué no tenerlo integrado en Visual Studio para macOS?.

Git History

Git History llega como addin para Visual Studio para macOS como una forma alternativa sencilla y rápida de ver el historial de cambios de un fichero.

¿Cómo instalar?

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

Buscamos por “Git History”.

Instalar…

Y pulsamos Install…

¿Qué aporta?

Haciendo clic derecho sobre cualquier archivo de un proyecto que use Git tendremos una nueva opción:

Show Git History

Lo que nos abrirá una nueva vista con el historial del archivo:

Viendo el historial del archivo

Veamos como usar el addin directamente:

Usando Git History

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

[VS4Mac] Nuevo addin para lanzar el terminal

Introducción

Tarde o temprano, el terminal acaba siendo un gran aliado. Hacer push en git, acceder a un archivo, ejecutar un script, etc. Las posibilidades son muy variadas.

Open Terminal

Open Terminal es un addin para Visual Studio para macOS que permite abrir el terminal directamente desde el IDE de forma rápida y sencilla.

¿Cómo instalar?

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

Buscamos por “Open Terminal”:

Instalar

Y pulsamos Install…

¿Qué aporta?

Poder abrir el terminal desde el IDE directamente. Podemos hacer clic derecho sobre cualquier proyecto o carpeta para abrir el terminal estando ya en dicha carpeta:

Usando una ruta específica

De modo que, tendremos el terminal abierto con la carpeta seleccionada prepara directamente para ejecutar comandos!.

Terminal

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

[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.Forms paso 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 (FFImageLoading con transformaciones, ImageCirclePlugin o 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?

SkiaSharp suele 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.Forms a 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 ClipPath para 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 TaskHeaderTemplate es un ContentView con la definición de la cabecera.

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>
                    <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 ViewCell personalizada. 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 ContentView que 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 GestureRecognizers para 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 Beech que Ricardo Vasquez ha 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