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.
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.
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:
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.
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.
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.
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:
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.
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:
El pasado 26 de Septiembre, teníamos en SVQXDGun 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:
Xamarin.Formsañade una capa de abstracción sobre la capa de la interfaz de usuario permitiendo definir la misma una única vez siendo válida para todas las plataformas.
Xamarin.Forms
A pesar de definir la interfaz de usuario una única vez para todas las plataformas, tenemos la posibilidad de realizar personalizaciones y adaptaciones para ofrecer la mejor experiencia posible en cada una de las plataformas soportadas.
La clase Device
La clase Devicesin duda alguna es una de las claves a la hora de personalizar la interfaz de usuario por plataforma. Esta clase contiene diversas propiedades y métodos para personalizar la UI y la funcionalidad en base a la plataforma.
Hasta ahora…
Dentro de la clase Device, la propiedad OSpermitía identificar la plataforma en la que se ejecuta la aplicación. La extensión demarcado OnPlatformpermite personalizar la interfaz por plataforma. La extensión OnPlatform esta soportada por la clase OnPlatformExtension (se permite la abreviatura OnPlatform desde XAML) que define las siguientes propiedades:
Default: Representa el valor por defecto que aplica a todas las plataformas.
Android: Valor aplicado en Android.
GTK: Valor aplicado en plataformas GTK.
iOS: Valor aplicado en iOS.
macOS: Valor aplicado en macOS.
Tizen: Valor aplicado en plataformas Tizen.
UWP: Valor aplicado en Universal Windows Platform
WPF: Valor aplicado en la plataforma Windows Presentation Foundation.
La extensión de marcado OnIdiompermite realizar personalizaciones de la apariencia basadas en el tipo de dispositivo donde corre la App. Soportado por la clase OnIdiomExtension define las siguientes propiedades:
Default: Valor por defecto, aplicado a todos los dispositivos.
Phone: Valor aplicado a teléfonos.
Tablet: Valor aplicado a tabletas.
Desktop: Aplicado a plataformas de escritorio.
TV: Valor aplicado a plataformas TV.
Watch: En este caso, el valor se aplica a plataformas Watch.
La StatusBar es un área importante de cara al usuario final. Disponible para mostrar información importante relacionada con el estado del sistema (hora, batería, red, etc.) además de notificaciones de otras aplicaciones.
StatusBar
Al desarrollar aplicaciones móviles, entre los objetivos, debemos conseguir un estilo único y uniforme. Para conseguirlo, en ocasiones será necesario modificar el aspecto de la StatusBar o incluso cambiarlo de forma uniforme para adaptarla a diferentes páginas de nuestra aplicación.
¿Cómo personalizamos la StatusBar?. En este artículo vamos a crear un efecto de Xamarin.Forms para personalizar la StatusBar en Android, iOS y en UWP.
Efectos
Un efecto permite el acceso al control nativo de cada plataforma con el objetivo de personalizarlo, principalmente aplicando pequeños cambios estéticos o de comportamiento. Permiten simplificar la personalización del control y sobretodo se convierten en “piezas” reutilizables de código incluso aceptando parametrización.
Crear un efecto
El proceso de creación de un efecto, se puede resumir en una serie de sencillos pasos:
Crear en la libería .NET Standard una clase que herede de RoutingEffect. Código independiente de la plataforma encargado de hacer el wrapping del efecto. Podemos definir distintas propiedades que permitan modificar la acción realizada por el efecto. Por ejemplo, en un efecto encargado de aplicar Blur a una imagen, se puede definir una propiedad encarga de aplicar mayor o menor distorsión.
Crear clases en cada plataforma soportada que hereden de PlatformEffect.
Sobrecargar el método OnAttached y añadir la lógica de personalización del control.
Sobrecargar el método OnDetached y añadir lógica de liberación de recursos.
Añadir el atributo ResolutionGroupName. Este atributo permite establecer el nombre del creador o compañia tras el efecto. Recuerda que uno de los objetivos fundamentales de los efectos es lograr permitir compartir y reutilizar con suma facilidad. Con este atributo se previenen colisiones con otros efectos que compartan nombre.
Añadir el atributo ExportEffect. Este atributo registra el efecto con un identificador único usado por Xamarin.Forms, junto al nombre del grupo, permite localizar y aplicar el efecto.
Definición del efecto
Comenzamos con la definición del efecto. Creamos una clase que hereda de RoutingEffect:
public class StatusBarEffect : RoutingEffect
{
public Color BackgroundColor { get; set; }
public StatusBarEffect() : base("Xamarin.StatusBarEffect")
{
}
}
Fíjate que definimos una propiedad de tipo Color llamada BackgroundColor que nos permitirá establecer el color de la StatusBar.
Android
En Android, accedemos a la Window de la actividad, para modificar el color de la StatusBar utilizando el método SetStatusBarColor:
var statusBarEffect = (StatusBarXamarinForms.Effects.StatusBarEffect)Element.Effects.FirstOrDefault(e => e is StatusBarXamarinForms.Effects.StatusBarEffect);
if (statusBarEffect != null)
{
var backgroundColor = statusBarEffect.BackgroundColor.ToAndroid();
Window currentWindow = GetCurrentWindow();
currentWindow.SetStatusBarColor(backgroundColor);
}
Convertimos el color de Xamarin.Forms a Android utilizando la extensión ToAndroid. Mientras que, para tener acceso de forma sencilla a la actividad actual, usamos el plugin CurrentActivityPlugin:
var window = CrossCurrentActivity.Current.Activity.Window;
iOS
En iOS, accedemos a la StatusBar, y le establecemos el color de fondo utilizando la propiedad BackgroundColor:
if (statusBarEffect != null)
{
UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = statusBarEffect.BackgroundColor.ToUIColor();
}
}
En este caso, el color lo convertimos a un UIColor con la extensión ToUIColor.
UWP
En el caso de UWP, contemplamos dos posibilidades:
En los últimos tiempos, la mejora de Xamarin.Forms tanto en posibilidades a nivel de UI (VisualStateManager, FlexLayout, etc.) como a nivel de renderers y rendimiento (a destacar en Android) ha sido importante.
Realmente, 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.
Es cada vez mayor el recopilatorio de ejemplos Open Source con Xamarin.Forms buscando interfaces complejas:
En este evento, vamos a analizar entre todos, abriendo debate e intercambiando ideas algunos de los ejemplos revisando opciones disponibles para conseguir ciertos resultados. Hablaremos de opciones como efectos, Custom Renderers, SkiaSharp, VisualStateManager, etc.
El lugar
El evento se celebrará en la ETS de Ingeniería Informática.
ETS de Ingeniería Informática
Dirección detallada:
E.T.S. Ingeniería Informática – Universidad de Sevilla, Aula B1.32 Av. Reina Mercedes s/n Sevilla Se 41012
La fecha
Será el próximo Miércoles, 26 de Septiembre de 19:00h a 20:30h (GMT+1).
La evolución de Xamarin.Forms es meritoria. En los últimos tiempos se han recibido novedades interesantes como efectos, vistas nativas, Forms Embedding, FlexLayout, etc. Sin embargo, en muchos casos se sigue asociado a desarrollos muy simples o formularios básicos.
Realmente, 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 Dribble, que intentaremos replicar con Xamarin.Forms paso a paso.
Music Player
Carátula circular
Comenzamos por una de las partes principales de la vista, la carátula circular. Vamos a utilizar FFImageLoading junto a las opciones de transformación disponibles:
Tenemos un botón totalmente circular. Podríamos al igual que la barra de progreso circular, crearlo con SkiaSharp facilmente. Sin embargo, si queremos contar con un botón, debemos crear un Custom Renderer.
Contamos con un botón circular preparado para utilizar con ButtonCirclePlugin. Tras añadir el paquete NuGet, añadimos el namespace:
La única parte con mayor complejidad de la animación, es que:
Por un lado mientras se esta reproduciendo la música, debe estar en ejecución en bucle.
Por otro lado, si el usuario pausa la reproducción o bien, la canción termina; se debe pausar o detener la animación.
Para la reproducción en bucle utilizamos una Task donde repetimos la misma animación. Para cancelar la Task hacemos uso de CancellationTokenSource. Para pausar la animación usamos:
ViewExtensions.CancelAnimations(CoverImage);
Progreso circular
Sin duda alguna, una de las claves de la vista es la barra de progreso circular. Por un lado, podemos irnos a por Custom Renderer y aprovechar código nativo en cada plataforma. Si queremos conseguir todo sólo con código compartido podríamos conseguir una barra circular de forma sencilla con imágenes y rotaciones, por ejemplo.
En este caso, vamos a utilizar SkiaSharp.
public class CircleProgress : SKCanvasView
{
}
Para dibujar el progreso circular, utilizaremos el método DrawPath para dibujar un Path al que le daremos la forma deseada utilizando el método AddArc.
FFImageLoading – Con el objetivo principal de gestionar la carátula circular. Esta librería también nos facilita importante funcionalidad relacionada con el cacheo de imágenes, etc. Aunque recuerda, en este ejemplo todas las imágenes son locales.
ButtonCirclePlugin – De forma sencilla permite crear botones circulares. Ideal para el botón central que gestiona Play/Pause. Además, soporta directamente iconos con algunas de las fuentes más utilizadas.
Y llegamos a la parte final del artículo. Es un concepto de artículo que ya hemos realizado previamente con la creación de la interfaz de Netflix, por ejemplo. Es sumamente divertido preparar un diseño con cierto nivel de “reto” e intetar “desgranar” cada paso a realizar. Pero, ¿qué te parece este tipo de artículos?.
Cualquier duda o comentario es bienvenido en los comentarios!
La evolución de Xamarin.Forms es meritoria. En los últimos tiempos se han recibido novedades interesantes como efectos, vistas nativas, Forms Embedding, FlexLayout, etc. Sin embargo, en muchos casos se sigue asociado a desarrollos muy simples o formularios básicos.
Realmente, 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 Dribble, que intentaremos replicar con Xamarin.Forms paso a paso.
Countdown Timer
Lo primero que debemos realizar, es un breve análisis de la pantalla:
Simplificando, estamos ante un contador hacia atrás, en concreto, hacia una fecha. En Xamarin.Forms contamos con la clase Device, una clase importante que nos facilita información importante como si estamos en una plataforma u otra, o si ejecutamos la App en teléfono o tableta. Además, Device cuenta con un Timer que podemos utilizar para la cuenta atrás, entre otras opciones.
De lo que más llama la atención de la simple interfaz de usuario, son los degradados. La línea de progreso circular es candidata a realizarse con SkiaSharp. A pesar de poder abordarla con un Custom Renderer, SkiaSharp nos facilitará dibujarla una única vez para todas las plataformas. El botón, a pesar de poder abordarlo también con SkiaSharp, vamos a realizarlo en nativo para poder contar con los diferentes estados, etc. En este caso, vamos a necesitar Custom Renderer o plugin de comunidad.
La carátula circular no es compleja. Entre en conjunto de posibilidades que tenemos, FFImageLoading gana enteros por su facilidad de uso, opciones de cache además de transformaciones.
La rotación de la carátula es una sencilla animación de rotación. Xamarin.Forms cuenta con una API de animaciones bastante completa.
¿Manos a la obra?
Imagen circular
Comenzamos por una de las partes principales de la vista, la imagen circular. Vamos a utilizar FFImageLoading junto a las opciones de transformación disponibles:
Sin duda alguna, la clave de la vista es la barra de progreso circular… y con degradado!. Por un lado, podemos irnos a por Custom Renderer y aprovechar código nativo en cada plataforma. Si queremos conseguir todo sólo con código compartido podríamos conseguir una barra circular de forma sencilla con imágenes y rotaciones, por ejemplo. Sin embargo, necesitamos diferentes recursos gráficos para adaptarnos a diferentes resoluciones. Por otro lado, el degradado añade complejidad.
¿La solución sencilla?
SkiaSharp. Engine gráfico 2D disponible para iOS, Android, UWP, macOS, Windows, etc.
Nos permite trabajar de forma sencilla desde co n figuras básicas a efectos y shaders más complejos.
En este caso, vamos a crear un control personalizado que herede de la clase SKCanvasView.
SKCanvasView es una vista Xamarin.Forms donde podremos dibujar utilizando SkiaSharp.
public class CircleCountdown : SKCanvasView
{
}
Vamos a crear varias BindableProperties para gestionar el comportamiento y apariencia de la barra de progreso:
public static readonly BindableProperty StrokeWidthProperty =
BindableProperty.Create(nameof(StrokeWidth), typeof(float), typeof(CircleCountdown), 10f, propertyChanged: OnPropertyChanged);
public static readonly BindableProperty ProgressProperty =
BindableProperty.Create(nameof(Progress), typeof(float), typeof(CircleCountdown), 0f, propertyChanged: OnPropertyChanged);
public static readonly BindableProperty ProgressStartColorProperty =
BindableProperty.Create(nameof(ProgressStartColor), typeof(Color), typeof(CircleCountdown), Color.Blue, propertyChanged: OnPropertyChanged);
public static readonly BindableProperty ProgressEndColorProperty =
BindableProperty.Create(nameof(ProgressEndColor), typeof(Color), typeof(CircleCountdown), Color.Red, propertyChanged: OnPropertyChanged);
public float StrokeWidth
{
get { return (float)GetValue(StrokeWidthProperty); }
set { SetValue(StrokeWidthProperty, value); }
}
public float Progress
{
get { return (float)GetValue(ProgressProperty); }
set { SetValue(ProgressProperty, value); }
}
public Color ProgressStartColor
{
get { return (Color)GetValue(ProgressStartColorProperty); }
set { SetValue(ProgressStartColorProperty, value); }
}
public Color ProgressEndColor
{
get { return (Color)GetValue(ProgressEndColorProperty); }
set { SetValue(ProgressEndColorProperty, value); }
}
Contamos con:
StrokeWidth: Permite controlar el grosor de la barra de progreso.
Progress: Determina el progreso. Acepta un valor numérico entre 0 y 1.
ProgressStartColor: ¿Recuerdas la necesidad de crear degradado?. Por ese motivo, vamos a contar con esta propiedad para gestionar el color de inicio del degradado.
ProgressEndColor: Color final del degradado.
Para dibujar el progreso circular, utilizaremos el método DrawPath para dibujar un Path al que le daremos la forma deseada utilizando el método AddArc.
using (SKPath path = new SKPath())
{
path.AddArc(rect, StartAngle, angle);
canvas.DrawPath(path, paint);
}
¿Y el degradado?.
En lugar de utilizar un SKColor (color en SkiaSharp) sólido, vamos a crear un shader. Utilizaremos el método CreateSweepGradient para crear el degradado:
El progreso lo tenemos enlazado a una propiedad en la ViewModel donde se irá realizando el cálculo del progreso.
Botón con degradado
Llegamos al botón con degradado. Podríamos al igual que la barra de progreso circular, crearlo con SkiaSharp facilmente. Sin embargo, un botón cuenta con estados que tienen importancia. Habilitado, deshabilitado, pulsado, etc. Si queremos contar con un botón, debemos crear un Custom Renderer. No es complejo haciendo un Custom Renderer del botón y utilizando RippleDrawable con GradientDrawable en Android, y CAGradientLayer en iOS.
Sin embargo, la comunidad de Xamarin es fantástica. Contamos con un botón con degradado preparado para utilizar con Skor.UI. Tras añadir el paquete NuGet, añadimos el namespace:
De nuevo, muy sencillo esta parte de la interfaz, ¿verdad?.
Otros
Y no hay que olvidar que estamos haciendo un contador hacia atrás. ¿Formas de conseguirlo?. Tenemos diferentes opciones, directamente en Xamarin.Forms, tenemos el método StartTimer en la clase Device:
FFImageLoading – Con el objetivo principal de gestionar la imágen circular. Esta librería también nos facilita importante funcionalidad relacionada con el cacheo de imágenes, etc. Aunque recuerda, en este ejemplo todas las imágenes son locales.
SKOR.UI – Nos facilita la creación de botones con degradados evitandonos crear un Custom Renderer.
Y llegamos a la parte final del artículo. Es un concepto de artículo que ya hemos realizado previamente con la creación de la interfaz de Netflix, por ejemplo. Es sumamente divertido preparar un diseño con cierto nivel de “reto” e intetar “desgranar” cada paso a realizar. Pero, ¿qué te parece este tipo de artículos?.
Cualquier duda o comentario es bienvenido en los comentarios!
Xamarin.Forms añade una capa de abstracción en la capa de UI que nos permite definir la misma una única vez para todas las plataformas. Podemos definir esta interfaz con código C# o XAML. El soporte de Linux (GTK) ahora está disponible en Xamarin.Forms.
Para conocer y revisar las diferentes opciones disponibles, ¿algo mejor que contar con ejemplos?
Ejemplos Xamarin.Forms.Platform.GTK
El repositorio de ejemplos oficial de Xamarin.Forms es una fuente inmejorable de ejemplos cubriendo desde ejemplos básicos a uso de SkiaSharp, SQlite, gestos, efectos, etc. A continuación, puedes encontrar un repositorio donde encontrar la mayoría de ejemplos (y creciendo!) con versión GTK.