[Xamarin.Forms] Introducción a TemplateUI

El orgien

Con el soporte a Shapes y Brushes en Xamarin.Forms quería explorar las posibilidades para poder crear controles personalizados directamente con Xamarin.Forms (sin usar Custom Renderers, SkiaSharp, etc.). Tras crear algunas pruebas, combinar todo con la posibilidad de usar ControlTemplate (plantillas para personalizar la definición del control), etc. nace TemplateUI.

Nace TemplateUI

TemplateUI es una librería que contiene diversos controles, todos ellos, permitiendo el uso de ControlTemplate.

TemplateUI

Las plantillas de control de Xamarin.Forms permiten definir la estructura visual de los controles. Permiten separar la interfaz de usuario del control de la lógica que implementa el control. También se puede insertar contenido adicional en el control con la plantilla en un lugar predefinido. Por ejemplo, se puede acceder a la plantilla que define el control Rate y hacer modificaciones para cambiar la orientación o aplicar un borde. Hablamos de opciones que mediante propiedades no se pueden personalizar.

AvatarView

Es una representación visual de la imagen de usuario que se puede personalizar con texto, imagen, etc.

BadgeView

Control usado para notificar al usuario con notificaciones o cambios de estado.

CarouselView

Permiten navegar entre una colección de vistas.

ChatBubble

Muestra un mensaje con la forma de un bocadillo de conversación de chat.

CircleProgressBar

Es un control que muestra el porcentaje de progreso en una forma circular.

ComparerView

Es un control que permite mostrar dos vistas (puede ser cualquier tipo de contenido) para realizar una comparativa lado a lado.

ComparerView

DataVisualization

Un conjunto de gráficas creadas usando Shapes. Contiene:

  • Line Chart
  • Area Chart
  • Bar Chart

GridSplitter

Control que permite redistribuir el espacio entre las columnas o filas de un Grid.

Marquee

Usa este control al querer llamar la atención del usuario; añade un texto que hara scroll de forma automática y continua por la pantalla.

ProgressBar

Representa una barra de progreso horizontal que se va rellenando en base a un valor de tipo float.

ProgressBar

Rate

Permite al usuario seleccionar un valor de un grupo de símbolos visuales como una estrella.

SegmentedControl

Es un segmento lineal creado con un conjunto de segmentos que permiten al usuario seleccionar una opción.

Shield

Shield es un tipo de badge.

Slider

Es una barra horizontal que puede ser manipulada para seleccionar un valor de tipo doble entre un rango de opciones.

Slider

Tag

Control para crear tags.

ToggleSwitch

Un control que permite al usuario manipular para alternar entre los estados on y off, que están representados por un valor de tipo boolean.

ToggleSwitch

TreeView

Permite crear una lista con jerarquía de modo que se puede expandir o contraer los nodos que contienen otros nodos anidados.

¿Qué es lo próximo?

Como puedes ver, ya hay una gran cantidad de controles y vienen mas en camino!. En próximos artículos conoceremos cómo usar los controles, opciones de personalización con propiedades y usando plantillas de control, etc.

Más información

[Xamarin.Forms] Brushes

Introducción

Con la llegada de Xamarin.Forms 4.8 llega una funcionalidad altamente esperada, la posibilidad de usar Brushes o lo que es lo mismo, gradientes. En este artículo, vamos a conocer las nuevas posibilidades que tenemos usando brushes.

Brushes

Podemos usar un Brush para pintar el interior y el contorno (en algunos casos) de las vistas, Layouts y formas que componen la interfaz de usuario.

Para usar un gradiente en el fondo de cualquier View, podemos usar la propiedad Fill que espera un valor de tipo Brush. Tenemos las siguientes opciones:

  • SolidColorBrush
  • LinearGradientBrush
  • RadialGradientBrush

SolidColorBrush

SolidColorBrush pinta un área con un único color, como por ejemplo rojo o azul. Se trata del Brush más básico. Desde código XAML podemos usar SolidColorBrush de diferentes maneras:

  • Creando un objeto de tipo SolidColorBrush.
  • Usando una cadena que de formato al color que define al Brush (Ejemplo, color hexadecimal).

Veamos ejemplos:

<Grid
     Background="#FF9988"/>

En el ejemplo anterior, gracias a un TypeConverter podemos definir el Brush de forma sencilla, de forma similar a establecer un color de fondo.

<SolidColodBrush x:Key="MyBrush" Color="#FF9988" />


<Grid
     Background="{StaticResource MyBrush}"/>

LinearGradientBrush

LinearGradientBrush pinta un área con un degradado que se define a lo largo de una línea. Esta línea es el eje de degradado. Los colores del degradado y su ubicación en el eje de degradado se especifican con objetos de tipo GradientStop.

NOTA: Por defecto, el eje de degradado va de la esquina superior izquierda a la esquina inferior derecha, es decir, se crea un degradado en diagonal.

Cada GradientStop especifica el Color que se utiliza en el eje hasta cierto Offset. El color se puede establecer usando un nombre de color predefinido o mediante valores mientras que la propiedad Offset especifica la posición de cada GradientStop en el eje de degradado. Un objeto Offset es de tipo double con valores entre 0 y 1. Un Offset con un valor de 0 sitúa el GradientStop al principio del eje de degradado; es decir, cercano a su StartPoint. Por otro lado, un Offset con un valor de 1 sitúa el GradientStop en su EndPoint.

Para cambiar la dirección del degradado usamos las propiedades StartPoint y EndPoint. Podemos crear degradados horizontales o verticales, invertir el sentido de degradado, etc.

Veamos un ejemplo:

<LinearGradientBrush 
     StartPoint="0, 0" EndPoint="1, 0">
     <LinearGradientBrush.GradientStops>
          <GradientStop Color="Red" Offset="0.1" />
          <GradientStop Color="Pink" Offset="1.0" />
     </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

El resultado:

LinearGradientBrush

RadialGradientBrush

Dibuja un degradado radial definido por las propiedades Center, RadiusX y RadiusY. El origen del degradado se establece usando la propiedad Center.

NOTA: Los colores del degradado se inician en el centro de la elipse y terminan en el radio.

Al igual que usando LinearGradientBrush, los colores del degradado radial se definen creando una colección de GradientStops.

Veamos un ejemplo:

<RadialGradientBrush 
     Center="0.5, 0.5">
     <RadialGradientBrush.GradientStops>
          <GradientStop Color="Red" Offset="0.1" />
          <GradientStop Color="Pink" Offset="1.0" />
     </RadialGradientBrush.GradientStops>
</RadialGradientBrush>

El resultado:

RadialGradientBrush

Gradientes en todas partes!

VisualElement cuenta ahora con una nueva propiedad Background esperando un objeto de tipo Brush. ¿Qué quiere decir esto?. Significa que cualquier View en Xamarin.Forms, es decir, en los controles, layouts e incluso páginas podemos usar gradientes ahora.

E incluso en NavigationPage o TabbedPage:

Gradientes en todas partes!

O usando Shapes:

Gradientes en Shapes

NOTA: Puedes notar que al usar Shapes se pueden usar brushes no solo para rellenar la figura, también para definir el contorno.

Usando CSS

Podemos definir brushes en código XAML y C#, pero en Xamarin.Forms también podemos configurar la apariencia de la aplicación usando CSS. Llega también el soporte a brushes usando CSS.

Veamos un ejemplo:

.linearGradientStyleWithCss90deg {
background: linear-gradient(90deg, rgb(255, 0, 0) 0%,rgb(255, 153, 51) 60%);
}

.linearGradientStyleWithCss180deg {
background: linear-gradient(180deg, rgb(255, 0, 0) 0%,rgb(255, 153, 51) 60%);
}

.linearGradientStyleWithCss270deg {
background: linear-gradient(270deg, rgb(255, 0, 0) 0%,rgb(255, 153, 51) 60%);
}

.radialGradientStyleWithCss {
background: radial-gradient(circle, rgb(255, 0, 0) 25%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 75%);
}

.radialGradientStyleWithCssLeft {
background: radial-gradient(circle at left, rgb(255, 0, 0) 25%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 75%);
}

.radialGradientStyleWithCssRight {
background: radial-gradient(circle at right, rgb(255, 0, 0) 25%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 75%);
}

El resultado:

Usando CSS

En las últimas versiones de Xamarin.Forms hemos ido recibiendo algunas novedades relacionadas puramente con las posibilidades a la hora de crear interfaces de usuario personalizadas. Funcionalidad como shapes, poder hacer clip de vistas o brushes permiten un número mayor de posibilidades para personalizar la interfaz de usuario y también a la hora de crear controles personalizados.

¿Qué te parecen estas novedades?. Recuerda, puedes dejar tu duda o pregunta en los comentarios de la entrada.

Más información

[Xamarin.Forms] Recortar vistas (Clip)

La llegada de Shapes a Xamarin.Forms

Con la llegada de Xamarin.Forms 4.7 nos llega la posibilidad de dibujar formas. Sin embargo, ¿sabías que además de poder dibujar una forma podemos cortar cualquier vista con una forma específica?. En este artículo, vamos a aprender cómo cortar vistas con formas.

Clip

La clase VisualElement cuenta ahora con una nueva propiedad llamada Clip de tipo Geometry que define el contorno del contenido.

La clase Geometry (y las clases que derivan de ella) permiten describir la geometría de una forma 2D.

En Xamarin.Forms contamos con geometrías simples como EllipseGeometry, LineGeometry o RectangleGeometry y geometrías más complejas como PathGeometry.

De modo que podemos recortar una imagen para tener una imagen circular de forma sencilla de la siguiente forma:

<Image 
     Source="image.png">
     <Image.Clip>
          <EllipseGeometry 
               RadiusX="100"
               RadiusY="100"
               Center="180,180" />
     </Image.Clip>
</Image>

Ejemplo:

Recortando imágenes!

Se pueden utilizar desde geometrías básicas a complejas usando un Path para definir exactamente la forma deseada.

Pero…funciona con cualquier View!

¿Recuerdas que mencionamos que la propiedad Clip estaba definido en VisualElement?. Esto se traduce en poder recortar cualquier tipo de vista en Xamarin.Forms, no solo imágenes.

Clip Views

De igual forma, recortar dinámicamente cualquier vista y también deshacer el recorte.

Clip Views dinámicamente

Añadir:

var ellipseGeometry = new EllipseGeometry
{
     Center = new Point(75, 75),
     RadiusX = 60,
     RadiusY = 60
};

Image.Clip = ellipseGeometry;

Quitar:

Image.Clip = null;

¿Qué te parece esta funcionalidad?. Recuerda, cualquier duda o comentario es bienvenido en la entrada.

Más información

Microsoft Docs: Xamarin.Forms Shapes

[Xamarin.Forms] Trucos y consejos a la hora de trabajar con Shapes

Trucos y consejos a la hora de trabajar con Shapes

Desde Xamarin.Forms 4.7 contamos en el namespace Xamarin.Forms.Shapes con soporte a dibujar formas en la pantalla en Android, iOS, macOS, UWP y WPF.
Contamos con formas sencillas pero también opciones más complejas que nos permiten dibujar practicamente lo que queramos. Pero…¿cómo dibujamos una forma específica?. En este artículo vamos a conocer trucos y consejos a la hora de conseguir dibujar formas en Xamarin.Forms.

De diseño a Shapes

A la hora de desarrollar aplicaciones móviles, un muchas ocasiones se parte de un diseño. Hay una enorme variedad de herramientas de diseño como Figma, Adobe XD o Sketch por ejemplo. En algunos casos existen plugins para exportar a XAML aunque lo que se cuenta en todas ellas, es la posibilidad de exportar a SVG¿Sabías que podemos convertir cualquier SVG a un Shape de forma sencilla?.
Por ejemplo, tomemos un SVG relativamente complejo compuesto por diferentes paths:
<svg viewBox='0 0 104 97' xmlns='http://www.w3.org/2000/svg'>
<path d='M14,85l3,9h72c0,0,5-9,4-10c-2-2-79,0-79,1' fill='#7C4E32'/>
<path d='M19,47c0,0-9,7-13,14c-5,6,3,7,3,7l1,14c0,0,10,8,23,8c14,0,26,1,28,0c2-1,9-2,9-4c1-1,27,1,27-9c0-10,7-20-11-29c-17-9-67-1-67-1' fill='#E30000'/>
<path d='M17,32c-3,48,80,43,71-3 l-35-15' fill='#FFE1C4'/>
<path d="M17,32c9-36,61-32,71-3c-20-9-40-9-71,3" fill="#8ED8F8"/>
<path d='M54,35a10 8 60 1 1 0,0.1zM37,38a10 8 -60 1 1 0,0.1z' fill='#FFF'/>
<path d='M41,6c1-1,4-3,8-3c3-0,9-1,14,3l-1,2h-2h-2c0,0-3,1-5,0c-2-1-1-1-1-1l-3,1l-2-1h-1c0,0-1,2-3,2c0,0-2-1-2-3M17,34l0-2c0,0,35-20,71-3v2c0,0-35-17-71,3M5,62c3-2,5-2,8,0c3,2,13,6,8,11c-2,2-6,0-8,0c-1,1-4,2-6,1c-4-3-6-8-2-12M99,59c0,0-9-2-11,4l-3,5c0,1-2,3,3,3c5,0,5,2,7,2c3,0,7-1,7-4c0-4-1-11-3-10' fill='#FFF200'/>
<path d='M56,78v1M55,69v1M55,87v1' stroke='#000' stroke-linecap='round'/>
<path d='M60,36a1 1 0 1 1 0-0.1M49,36a1 1 0 1 1 0-0.1M57,55a2 3 0 1 1 0-0.1M12,94c0,0,20-4,42,0c0,0,27-4,39,0z'/>
<path d='M50,59c0,0,4,3,10,0M56,66l2,12l-2,12M25,50c0,0,10,12,23,12c13,0,24,0,35-15' fill='none' stroke='#000' stroke-width='0.5'/>
</svg>
Dibuja al personaje Cartman de South Park. Podemos transformar el código anterior a XAML de forma muy sencilla:
<Grid>
     <Path Data="M14,85l3,9h72c0,0,5-9,4-10c-2-2-79,0-79,1" Fill="#7C4E32"/>
     <Path Data="M19,47c0,0-9,7-13,14c-5,6,3,7,3,7l1,14c0,0,10,8,23,8c14,0,26,1,28,0c2-1,9-2,9-4c1-1,27,1,27-9c0-10,7-20-11-29c-17-9-67-1-67-1" Fill="#E30000"/>
     <Path Data="M17,32c-3,48,80,43,71-3 l-35-15" Fill="#FFE1C4"/>
     <Path Data="M17,32c9-36,61-32,71-3c-20-9-40-9-71,3" Fill="#8ED8F8"/>
     <Path Data="M54,35a10 8 60 1 1 0,0.1zM37,38a10 8 -60 1 1 0,0.1z" Fill="#FFF"/>
     <Path Data="M41,6c1-1,4-3,8-3c3-0,9-1,14,3l-1,2h-2h-2c0,0-3,1-5,0c-2-1-1-1-1-1l-3,1l-2-1h-1c0,0-1,2-3,2c0,0-2-1-2-3M17,34l0-2c0,0,35-20,71-3v2c0,0-35-17-71,3M5,62c3-2,5-2,8,0c3,2,13,6,8,11c-2,2-6,0-8,0c-1,1-4,2-6,1c-4-3-6-8-2-12M99,59c0,0-9-2-11,4l-3,5c0,1-2,3,3,3c5,0,5,2,7,2c3,0,7-1,7-4c0-4-1-11-3-10" Fill="#FFF200"/>
     <Path Data="M56,78v1M55,69v1M55,87v1" Stroke="#000" StrokeLineCap="Round"/>
     <Path Data="M60,36a1 1 0 1 1 0-0.1M49,36a1 1 0 1 1 0-0.1M57,55a2 3 0 1 1 0-0.1M12,94c0,0,20-4,42,0c0,0,27-4,39,0z" Stroke="#000"/>
     <Path Data="M50,59c0,0,4,3,10,0M56,66l2,12l-2,12M25,50c0,0,10,12,23,12c13,0,24,0,35-15" Stroke="#000" StrokeThickness="0.5"/>
</Grid>
El resultado:

Dibujando usando SVG

Cada Path dibuja un elemento del personaje de modo que podemos aplicar transformaciones, animaciones, etc. a cada pequeña parte que compone el dibujo. Ah, recuerda que XAML Hot Reload funciona con Shapes:

Usando Hot Reload

Dibujando con herramientas

Una herramienta perfecta para crear Shapes es Blend. Entre el conjunto de Assets puedes directamente arrastrar y soltar cualquier tipo de Shape, y luego hacer cualquier transformación como rotar, escalar, etc.

Shapes

Dibujando Shapes con Blend

Otra herramienta clásica pero que nos permite dibujar y exportar directamente código XAML que podremos utilizar en nuestra aplicación Xamarin.Forms es Inkscape. Herramienta de dibujado disponible para Windows, macOS y Linux nos permite una gran variedad de opciones (que podemos extender usando plugins) para dibujar:

Inkscape

Y exportar el código directamente a XAML:
<?xml version="1.0" encoding="UTF-8"?>
<!--This file is NOT compatible with Silverlight-->
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="svg8" Width="210" Height="297">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas.Resources/>
<!--Unknown tag: sodipodi:namedview-->
<!--Unknown tag: metadata-->
<Canvas Name="layer1">
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path10" StrokeThickness="0.264583" Stroke="#FF000000">
<Path.Data>
<PathGeometry Figures="m 130.77975 114.90475 c -1.28867 2.76686 -4.36546 -0.37204 -4.5987 -2.14187 -0.63208 -4.79613 4.79124 -7.58089 8.88244 -7.05555 7.31819 0.93971 11.05326 8.94515 9.51239 15.62302 -2.26128 9.80005 -13.14527 14.60051 -22.36359 11.96923 -12.28658 -3.50708 -18.17801 -17.36047 -14.42608 -29.10417 4.72141 -14.778243 21.58254 -21.770781 35.84475 -16.882919 17.27344 5.919857 25.37235 25.808419 19.33976 42.585329 -7.1092 19.771 -30.03665 28.97944 -49.3259 21.7966 C 91.374607 143.40155 81.054615 117.42797 89.391371 95.627942 98.864123 70.857366 127.88874 59.424405 152.19843 68.917654 c 27.27179 10.649991 39.81874 42.729096 29.16713 69.547636 -11.82531 29.77366 -46.96143 43.43535 -76.28821 31.62397" FillRule="EvenOdd"/
</Path.Data>
</Path>
</Canvas>
</Canvas>
</Viewbox>
De modo que, podemos utilizar el resultado en nuestras aplicaciones:
<Path
     StrokeThickness="0.264583"
     Stroke="#FF000000">
     <Path.Data>
          <PathGeometry
               Figures="m 130.77975 114.90475 c -1.28867 2.76686 -4.36546 -0.37204 -4.5987 -2.14187 -0.63208 -4.79613 4.79124 -7.58089 8.88244 -7.05555 7.31819 0.93971 11.05326 8.94515 9.51239 15.62302 -2.26128 9.80005 -13.14527 14.60051 -22.36359 11.96923 -12.28658 -3.50708 -18.17801 -17.36047 -14.42608 -29.10417 4.72141 -14.778243 21.58254 -21.770781 35.84475 -16.882919 17.27344 5.919857 25.37235 25.808419 19.33976 42.585329 -7.1092 19.771 -30.03665 28.97944 -49.3259 21.7966 C 91.374607 143.40155 81.054615 117.42797 89.391371 95.627942 98.864123 70.857366 127.88874 59.424405 152.19843 68.917654 c 27.27179 10.649991 39.81874 42.729096 29.16713 69.547636 -11.82531 29.77366 -46.96143 43.43535 -76.28821 31.62397" FillRule="EvenOdd"/>
     </Path.Data>
</Path>

El resultado

Otras herramientas

Hay una enorme variedad de herramientas y posibilidades para trabajar con Shapes. Sin embargo, me gustaría también recomendar Metro Studio. Es una herramienta gratuita de SyncFusion que cuenta con más de 7000 iconos y formas diferentes que exportar a código XAML. Podemos aprovechar este código XAML para crear iconos usando Shapes y dibujar diferentes figuras.

Metro Studio

Snippets de código

Para facilitar la creación de Shapes puedes encontrar un listado de snippets para Visual Studio en este enlace.

Más información

[Xamarin.Forms] Tips and tricks working with Shapes

Tips and tricks working with Shapes

In Xamarin.Forms 4.7 we have in the Xamarin.Forms.Shapes namespace support to draw shapes on the screen in Android, iOS, macOS, UWP and WPF.
We have from simple shapes to more complex options that allow us to practically draw whatever we want. But … how do we draw a specific shape?. In this article we are going to learn tips and tricks to draw shapes in Xamarin.Forms.

From Design to Shapes

When developing mobile applications, some times sometimes we replicate a design. There is a huge variety of design tools such as Figma, Adobe XD or Sketch for example. In some cases there are plugins to export to XAML although what is available in all of them is the possibility of export to SVG format. Do you know that we can convert any SVG to a Xamarin.Forms Shape in a simple way?.
For example, let’s take a relatively complex SVG created with a composition of paths:
<svg viewBox='0 0 104 97' xmlns='http://www.w3.org/2000/svg'>
<path d='M14,85l3,9h72c0,0,5-9,4-10c-2-2-79,0-79,1' fill='#7C4E32'/>
<path d='M19,47c0,0-9,7-13,14c-5,6,3,7,3,7l1,14c0,0,10,8,23,8c14,0,26,1,28,0c2-1,9-2,9-4c1-1,27,1,27-9c0-10,7-20-11-29c-17-9-67-1-67-1' fill='#E30000'/>
<path d='M17,32c-3,48,80,43,71-3 l-35-15' fill='#FFE1C4'/>
<path d="M17,32c9-36,61-32,71-3c-20-9-40-9-71,3" fill="#8ED8F8"/>
<path d='M54,35a10 8 60 1 1 0,0.1zM37,38a10 8 -60 1 1 0,0.1z' fill='#FFF'/>
<path d='M41,6c1-1,4-3,8-3c3-0,9-1,14,3l-1,2h-2h-2c0,0-3,1-5,0c-2-1-1-1-1-1l-3,1l-2-1h-1c0,0-1,2-3,2c0,0-2-1-2-3M17,34l0-2c0,0,35-20,71-3v2c0,0-35-17-71,3M5,62c3-2,5-2,8,0c3,2,13,6,8,11c-2,2-6,0-8,0c-1,1-4,2-6,1c-4-3-6-8-2-12M99,59c0,0-9-2-11,4l-3,5c0,1-2,3,3,3c5,0,5,2,7,2c3,0,7-1,7-4c0-4-1-11-3-10' fill='#FFF200'/>
<path d='M56,78v1M55,69v1M55,87v1' stroke='#000' stroke-linecap='round'/>
<path d='M60,36a1 1 0 1 1 0-0.1M49,36a1 1 0 1 1 0-0.1M57,55a2 3 0 1 1 0-0.1M12,94c0,0,20-4,42,0c0,0,27-4,39,0z'/>
<path d='M50,59c0,0,4,3,10,0M56,66l2,12l-2,12M25,50c0,0,10,12,23,12c13,0,24,0,35-15' fill='none' stroke='#000' stroke-width='0.5'/>
</svg>
Draw the Cartman character from South Park. We can transform the previous code to XAML in a very simple way:
<Grid>
     <Path Data="M14,85l3,9h72c0,0,5-9,4-10c-2-2-79,0-79,1" Fill="#7C4E32"/>
     <Path Data="M19,47c0,0-9,7-13,14c-5,6,3,7,3,7l1,14c0,0,10,8,23,8c14,0,26,1,28,0c2-1,9-2,9-4c1-1,27,1,27-9c0-10,7-20-11-29c-17-9-67-1-67-1" Fill="#E30000"/>
     <Path Data="M17,32c-3,48,80,43,71-3 l-35-15" Fill="#FFE1C4"/>
     <Path Data="M17,32c9-36,61-32,71-3c-20-9-40-9-71,3" Fill="#8ED8F8"/>
     <Path Data="M54,35a10 8 60 1 1 0,0.1zM37,38a10 8 -60 1 1 0,0.1z" Fill="#FFF"/>
     <Path Data="M41,6c1-1,4-3,8-3c3-0,9-1,14,3l-1,2h-2h-2c0,0-3,1-5,0c-2-1-1-1-1-1l-3,1l-2-1h-1c0,0-1,2-3,2c0,0-2-1-2-3M17,34l0-2c0,0,35-20,71-3v2c0,0-35-17-71,3M5,62c3-2,5-2,8,0c3,2,13,6,8,11c-2,2-6,0-8,0c-1,1-4,2-6,1c-4-3-6-8-2-12M99,59c0,0-9-2-11,4l-3,5c0,1-2,3,3,3c5,0,5,2,7,2c3,0,7-1,7-4c0-4-1-11-3-10" Fill="#FFF200"/>
     <Path Data="M56,78v1M55,69v1M55,87v1" Stroke="#000" StrokeLineCap="Round"/>
     <Path Data="M60,36a1 1 0 1 1 0-0.1M49,36a1 1 0 1 1 0-0.1M57,55a2 3 0 1 1 0-0.1M12,94c0,0,20-4,42,0c0,0,27-4,39,0z" Stroke="#000"/>
     <Path Data="M50,59c0,0,4,3,10,0M56,66l2,12l-2,12M25,50c0,0,10,12,23,12c13,0,24,0,35-15" Stroke="#000" StrokeThickness="0.5"/>
</Grid>
The result:

Dibujando usando SVG

Each Path draws an element of the character so we can apply transformations, animations, etc. to each small part that makes up the drawing. Ah, remember that XAML Hot Reload works with Shapes:

Usando Hot Reload

Drawing with tools

A nice tool for creating Shapes is Blend. Among the set of Assets you can directly drag and drop any type of Shape, and then do any transformation like rotate, scale, etc.

Shapes

Dibujando Shapes con Blend

Another classic tool but that allows us to directly draw and export XAML code that we can use in our Xamarin.Forms application is Inkscape. Drawing tool available for Windows, macOS and Linux allows us a great variety of options (that we can extend using plugins) to draw:

Inkscape

And export the code directly to XAML:
<?xml version="1.0" encoding="UTF-8"?>
<!--This file is NOT compatible with Silverlight-->
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="svg8" Width="210" Height="297">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas.Resources/>
<!--Unknown tag: sodipodi:namedview-->
<!--Unknown tag: metadata-->
<Canvas Name="layer1">
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path10" StrokeThickness="0.264583" Stroke="#FF000000">
<Path.Data>
<PathGeometry Figures="m 130.77975 114.90475 c -1.28867 2.76686 -4.36546 -0.37204 -4.5987 -2.14187 -0.63208 -4.79613 4.79124 -7.58089 8.88244 -7.05555 7.31819 0.93971 11.05326 8.94515 9.51239 15.62302 -2.26128 9.80005 -13.14527 14.60051 -22.36359 11.96923 -12.28658 -3.50708 -18.17801 -17.36047 -14.42608 -29.10417 4.72141 -14.778243 21.58254 -21.770781 35.84475 -16.882919 17.27344 5.919857 25.37235 25.808419 19.33976 42.585329 -7.1092 19.771 -30.03665 28.97944 -49.3259 21.7966 C 91.374607 143.40155 81.054615 117.42797 89.391371 95.627942 98.864123 70.857366 127.88874 59.424405 152.19843 68.917654 c 27.27179 10.649991 39.81874 42.729096 29.16713 69.547636 -11.82531 29.77366 -46.96143 43.43535 -76.28821 31.62397" FillRule="EvenOdd"/
</Path.Data>
</Path>
</Canvas>
</Canvas>
</Viewbox>
So, we can use the result in our applications:
<Path
     StrokeThickness="0.264583"
     Stroke="#FF000000">
     <Path.Data>
          <PathGeometry
               Figures="m 130.77975 114.90475 c -1.28867 2.76686 -4.36546 -0.37204 -4.5987 -2.14187 -0.63208 -4.79613 4.79124 -7.58089 8.88244 -7.05555 7.31819 0.93971 11.05326 8.94515 9.51239 15.62302 -2.26128 9.80005 -13.14527 14.60051 -22.36359 11.96923 -12.28658 -3.50708 -18.17801 -17.36047 -14.42608 -29.10417 4.72141 -14.778243 21.58254 -21.770781 35.84475 -16.882919 17.27344 5.919857 25.37235 25.808419 19.33976 42.585329 -7.1092 19.771 -30.03665 28.97944 -49.3259 21.7966 C 91.374607 143.40155 81.054615 117.42797 89.391371 95.627942 98.864123 70.857366 127.88874 59.424405 152.19843 68.917654 c 27.27179 10.649991 39.81874 42.729096 29.16713 69.547636 -11.82531 29.77366 -46.96143 43.43535 -76.28821 31.62397" FillRule="EvenOdd"/>
     </Path.Data>
</Path>

El resultado

Other tools

There are a huge variety of tools and possibilities for working with Shapes. However, I would also like to recommend Metro Studio. It is a free SyncFusion tool that has more than 7000 different icons and shapes to export to XAML code. We can take advantage of this XAML code to create icons using Shapes and draw different shapes.

Metro Studio

Snippets

To facilitate the Shapes creation I created some snippets for Visual Studio. If you need guidance on how to implement snippets in Visual Studio 2019, head on over to the documentation guide.

More information

[Xamarin.Forms] Shapes

Shapes

Con la evolución de Xamarin.Forms las posibilidades creando interfaces de usuario o controles personalizados ha ido incrementando. Sin embargo, no tenemos aún la posibilidad de dibujar formas básicas (rectángulo, línea o círculo). Llegan Shapes a Xamarin.Forms!.

Un Shape es una vista que permite dibujar una forma en la pantalla. Los Shapes están disponibles en el namespace Xamarin.Forms.Shapes permitiendo dibujar formas en Android, iOS, macOS, UWP y WPF.

NOTA: Los Shapes actualmente están en fase experimental y para poder usarlos necesitas usar el flag Shapes_Experimental.

Todas las Shapes comparten una serie de propiedades comunes:

  • Aspect: Define cómo el Shape ocupa el espacio asignado.
  • Fill: Color de fondo de la figura.
  • Stroke: Color del borde de la figura.

Junto a otras propiedades como StrokeThickness, StrokeDashArray, etc.

Xamarin.Forms cuenta con diferentes objetos que derivan de la clase Shape como:

  • Rectangle
  • Ellipse
  • Line
  • Polyline
  • Polygon
  • Path

Rectangle

Es una forma con cuatro lados cuyos lados opuestos son iguales. Para crear un rectángulo básico, se debe especificar las propiedades WidthRequest, HeightRequest y Fill.

<Rectangle 
     Fill="Red"
     WidthRequest="150"
     HeightRequest="50"
     HorizontalOptions="Start" />

Rectangle cuenta con las propiedades:

  • RadiusX: Es el radio del eje x que se usa para redondear las esquinas del rectángulo.
  • RadiusY: Es el radio del eje y que se usa para redondear las esquinas del rectángulo.

Rectangle

Ellipse

Una elipse es una forma con un perímetro curvo. Para crear una elipse básica, hay que especificar el WidthRequest, HeightRequest y Fill.

<Ellipse 
     Fill="Red"
     WidthRequest="150"
     HeightRequest="50"
     HorizontalOptions="Start" />

Ellipse

Line

Permite dibujar una línea entre dos puntos. La línea se define con las siguientes propiedades:

  • X1: La coordenada X del punto inicial.
  • Y1: La coordenada Y del punto inicial.
  • X2: La coordenada X del punto final.
  • Y2: La coordenada Y del punto final.
<Line 
     X1="40"
     Y1="0"
     X2="0"
     Y2="120"
     Stroke="Red" />

Line

Polyline

Es similar a un polígono ya que el límite de la forma está definido por un conjunto de puntos, pero hay que tener en cuenta que el último punto de la polilínea no está conectado al primero.

  • Points: Es una colección de puntos que describen los puntos de vértice de la polilínea.
  • FillRule: Especifica cómo se combinan las áreas de intersección de la polilínea.
<Polyline Points="0,0 10,30, 15,0 18,60 23,30 35,30 40,0 43,60 48,30 100,30"
Stroke="Red" />

Polyline

Polygon

Es una forma con un límite definida por un número de puntos arbitrario. El límite se crea conectando una línea desde un punto al siguiente, con el último punto conectado al primero.

  • Points: Es una colección de puntos que describen los puntos de vértice del polígono.
  • FillRule: Especifica cómo se combinan las áreas de intersección del polígono.
<Polygon 
     Points="40,10 70,80 10,50"
     Fill="AliceBlue"
     Stroke="Green"
     StrokeThickness="5" />

Polygon

Path

Es la figura más versátil, ya que se puede usar para definir una geometría arbitraria.

<Path
     Stroke="Black" 
     Fill="Gray"
     Data="M 10,100 C 10,300 300,-200 300,100" />

Path

Geometrías

La clase Geometry (y las clases que derivan de ella) permiten describir la geometría de una forma 2D.

En Xamarin.Forms contamos con geometrías simples como EllipseGeometry, LineGeometry o RectangleGeometry y geometrías más complejas como PathGeometry.

<Path 
     Fill="Blue"
     Stroke="Red"
     StrokeThickness="1">
     <Path.Data>
     <EllipseGeometry 
          Center="50,50"
          RadiusX="50"
          RadiusY="50" />
     </Path.Data>
</Path>

Más información

[Xamarin.Forms] MultiBinding

MultiBinding

En Xamarin.Forms 4.7 se añade soporte a MultiBinding!. Pero… ¿qué es esto?.

MultiBinding describe una colección de objetos Binding asociados a una sola propiedad de destino de enlace. Permite enlazar una propiedad del destino de enlace a una lista de propiedades de origen y, a continuación, aplicar la lógica para generar un valor con las entradas indicadas.

Por ejemplo:

<Label>
     <Label.Text>
          <MultiBinding Converter="{StaticResource NameConverter}">
               <Binding Path="Name"/>
               <Binding Path="Surname"/>
          </MultiBinding>
     </Label.Text>
</Label>

Podemos componer un nuevo valor (en este caso es una cadena) en base los valores de diferentes enlace a datos. Es un ejemplo muy sencillo, pero veamos el resultado:

MultiBinding

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

¿Qué te parece la llegada de MultiBinding en Xamarin.Forms?, ¿qué te gustaría ver añadido en XAML?. Recuerda, puedes dejar cualquier duda o comentario en la entrada!.

Más información

Probar versiones previas y bug fixes de Xamarin.Forms

Introducción

Xamarin.Forms es un proyecto Open Source donde tú como desarrollador y como parte de la comunidad, puedes participar. Pero…¿sabes que el sistema de Builds también es público?. De esta forma, sí estas esperando una PR concreta o has enviado una PR con funcionalidad o con un corrección, puedes descargar los paquetes NuGet con los cambios y probarlos.

Xamarin.Forms no es una excepción cuenta con procesos automáticos de compilación y pruebas automatizadas. En este artículo, vamos a conocer como acceder a las Nightly Builds así como a la Build de una PR concreta.

Probar versiones previas

Todas las noches se realiza la compilación de la rama master y se publica un paquete NuGet en las Nightly Builds. Puedes acceder a las Nightly en este enlace:

https://aka.ms/xf-ci/index.json

Veamos como usarlo:

Visual Studio para Windows

  1. Abre las opciones de configuración navegando por Tools > NuGet Package Manager > Package Manager Settings.
  2. Selecciona la página de Package Sources.
  3. Haz click en el botón añadir.
  4. Añade un nombre personalizado y sobretodo, la URL de las Nightly Builds.
  5. Pulsa Ok.
  6. A la hora de usar NuGet Package Manager, elige tu fuente personalizada, y voila, podrás ver los paquetes disponibles en la Nightly.

Visual Studio para macOS

  1. Abe NuGet Package Manager navegando por el menu Project > Add NuGet Packages…
  2. Selecciona Configure Sources…
  3. Haz clic en el botón para añadir una nueva fuente.
  4. Introduce el nombre y la URL de la Nightly.
  5. Haz clic en  Add Source y luego en OK.

Probar bug fixes

Para cada PR, lo primero que se hace es una compilación para ver si todo compila correctamente. Cada vez que se lanza una compilación, se registran ver los pasos y se registra todo en el apartado de estado de Github.

Información de la Build en GitHub

La información de la Build la tienes disponible en xamarin-forms-ci, que es la compilación de CI de Azure DevOps.

Como parte de la compilación de CI, también se crean artefactos que son los paquetes NuGet que contienen el nuevo código. Para acceder a los artefactos comenzamos pulsando el enlace Details de xamarin-forms-ci.

Azure DevOps CI

Navegamos a Azure DevOps donde podemos ver los detalles de la Build, pruebas que han pasado, etc. Entre la información disponible, verás que hay 3 artefactos publicados. Haciendo clic sobre los artefactos navegamos a:

Los artefactos

Los detalles de artefactos generados. Tenemos cada paquete NuGet generado donde podremos encontrar desde el paquete de Xamarin.Forms como otros paquetes asociados como mapas, etc. Para descargar un paquete concreto, pulsamos los tres puntos suspensivos y elegimos la opción Download artifacts (Fíjate que también puedes obtener la URL hacia el artefacto).

Descargar artefacto

¿Y cómo lo usamos?. De una forma muy similar a la anterior. Creamos una origen de paquetes nuevo sencillamente usando una carpeta que contenga los artefactos descargados en lugar de usar una URL.

A tener en cuenta

Recuerda, puedes descargar el paquete NuGet de una PR en cuanto pasa el proceso de CI, es decir, todo compila y pasan las pruebas. Sin embargo, aún faltarían las revisiones de código y otras validaciones. Es decir, recuerda que están usando algo que puede cambiar o esta en fase Preview a falta de más validaciones.

Más información

[Xamarin.Forms] App Themes

Temas

Los dispositivos móviles incluyen la opción de usar un tema claro u oscuro a nivel de sistema operativo. Las aplicaciones pueden detectar y responder al cambio del tema del sistema.

NOTA: El tema del sistema puede cambiar por diversos motivos dependiendo de la la configuración del dispositivo. Además de la elección explícita por parte del usuario, puede cambiar en base a factores ambientales como un nivel bajo de luz.

En Xamarin.Forms 4.6 se añade AppTheme. Ahora las aplicaciones de Xamarin. Forms pueden responder a los cambios de tema usado por el sistema y en este artículo vamos a ver como hacerlo.

Definir y utilizar recursos por tema

Utilizando AppThemeColor podemos definir un color para los temas del sistema Light y Dark.

<AppThemeColor x:Key="ThemeColor" Light="DarkRed" Dark="LightPink" />

Podemos usar el color como hemos estado haciendo hasta ahora:

<Label 
     Text="AppTheme Color"
     TextColor="{DynamicResource ThemeColor}"/>

De forma automática se aplicará el color rojo oscuro usando el tema claro, y rosa claro al usar el oscuro. También podemos definir un AppThemeColor usando estilos utilizando la extensión de marcado OnAppTheme:

<Style x:Key="OSThemeStyle" TargetType="Label" >
     <Setter Property="TextColor" Value="{OnAppTheme Black, Light=DarkRed, Dark=LightPink}" />
</Style>

Aplicamos el estilo:

<Label 
     Text="Using Style"
     Style="{DynamicResource OSThemeStyle}"/>

Detectar el tema actual usado por el sistema

Podemos saber el tema usado por el sistema utilizando la propiedad Application.RequestedTheme:

OSAppTheme currentTheme = Application.Current.RequestedTheme;

Obtenemos un valor de tipo enumeración OSAppTheme. La enumeración puede tener uno de los siguientes valores:

  • Unspecified, que indica que el dispositivo está utilizando un tema no especificado.
  • Light, que indica que el dispositivo está usando el tema claro.
  • Dark, que indica que el dispositivo está usando el tema oscuro.

Reaccionar al cambio de tema

El tema usado por el puede cambiar y desde nuestra aplicación, podemos detectar el cambio. Para detectar el cambio de tema podemos usar el evento Application.RequestedThemeChanged:

Application.Current.RequestedThemeChanged += (s, a) =>
{
     AppTheme requestedTheme = a.RequestedTheme;
};

Puedes encontrar un ejemplo de AppTheme en GitHub:

Ver GitHub

¿Qué te parece esta nueva API?. Recuerda, puedes dejar un comentario con cualquier pregunta o duda!.

Más información

[Xamarin.Forms] Primer vistazo a Expander

Expander

Como en las últimas versiones de Xamarin.Forms, llega nueva versión y viene con algun nuevo control que permita expandir las posibilidades. En la versón 4.6-pre4 recibimos varias novedades de peso entre las que se incluyen el control Expander.

Expander proporciona un contenedor expandible para alojar cualquier contenido de modo que, se puede mostrar u ocultar este contenido interactuando con el encabezado.

Contamos con dos vistas diferenciadas:

  • Header: Cabecera que permitirá controlar el estado del control (si se encuentra expandido, colapsado, etc).
  • Content: El contenido que se puede expandir.

Veamos el uso básico del control:

<Expander>
     <Expander.Header>
          <Label Text="Header" />
     </Expander.Header>
     <ContentView x:Name="content"/>
</Expander>

De esta forma inicializamos y tenemos en el árbol visual tanto a la cabecera como al contenido. Sin embargo, también podemos hacer lazy loading del contenido usando ContentTemplate:

<Expander>
     <Expander.Header>
          <Label Text="Header" />
     </Expander.Header>
     <Expander.ContentTemplate>
          <DataTemplate>
               <ContentView x:Name="content"/>
          </DataTemplate>
     </Expander.ContentTemplate>
</Expander>

Podemos saber en todo momento el estado gracias a la propiedad IsExpanded (booleano que indica si el Expander esta expandido o no) y State. Los posibles valores de State son:

  • Expanding
  • Expanded
  • Collapsing
  • Collapsed

Una de las características fundamentales del control es el comportamiento al expandir o contraer, por ello, tenemos control en el tiempo y función Easing a utilizar en ambos casos:

  • ExpandAnimationLength: Duración de la animación al expandir.
  • CollapseAnimationLength: Duración de la animación al contraer.
  • ExpandAnimationEasing: Easing utilizado al expandir.
  • CollapseAnimationEasing: Easing utilizado al contraer.

NOTA: También por supuesto contamos con comando (Command y CommandParameter) y eventos (Tapped) para controlar cuando cambiamos el estado del Expander.

UI Challenge usando Expander

Una forma divertida de probar nueva funcionalidad, es hacer un UI Challenge utilizándola. En esta ocasión, vamos a crear una lista de la compra personalizada usando el nuevo control Expander basado en este diseño de Hila Peleg.

El diseño

Los retos del ejemplos

Los retos para conseguir esta lista de la compra son los siguientes:

  • Tenemos elementos organizados por categorías a los que accedemos expandiendo la categoría. Claramente, aquí el nuevo control Expander nos va a ayudar a conseguir la clave de la UI.
  • El indicator de cada categoría (círculo que rodea al icono de cada categoría) se expande al expandir los detalles. Para conseguir esos bordes redondeados podríamos usar un Frame sin necesidad de ningun plugin, o bien, podemos conseguir fácilmente utilizando PancakeView. Pero…¿como expandir?. Si recuerdas, el control Expander cuenta con una propiedad que nos indica si esta expandido o no. Vamos a utilizar esa propiedad para modificar CornerRadius y otras propiedades usando DataTriggers!.

Expandir elementos del listado de la compra

Comenzamos creando el listado de elementos. Dado que tendremos un listado relativamente pequeño de elementos (que se podrán expandir), vamos a utilizar Bindable Layout:

<ScrollView>
     <StackLayout
          BindableLayout.ItemsSource="{Binding Path=Items}">
          <BindableLayout.ItemTemplate>
               <DataTemplate>
                    <Expander>
                    ...
                    </Expander>
               </DataTemplate>
          </BindableLayout.ItemTemplate>
     </StackLayout>
</ScrollView>

Hemos definido un StackLayout que se encargará de apilar cada Expander. Fíjate que como padre hemos definido un ScrollView que nos permita tener scroll en caso necesario.

Así por cada categoría dentro del listado de la compra utilizaremos un Expander:

<Expander 
     ExpandAnimationEasing="{x:Static Easing.Linear}"
     CollapseAnimationEasing="{x:Static Easing.Linear}"
     IsExpanded="{Binding IsDetailVisible, Mode=TwoWay}">

Definimos Las propiedades básicas relacionadas con el comportamiento de expandir y contraer (animaciones) así como enlazar la propiedad clave para saber el estado del mismo, IsExpanded.

Pasamos a definir la cabecera:

<Expander.Header>
     <Grid 
     Style="{StaticResource ExpandeLayoutStyle}">
     <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="*" />
     </Grid.ColumnDefinitions>
     <Grid.RowDefinitions>
          <RowDefinition Height="*" />
          <RowDefinition Height="Auto" />
     </Grid.RowDefinitions>
          <pancakeview:PancakeView
               Grid.Column="0"
               BackgroundColor="{Binding Color}"
               Style="{StaticResource CollpasedColorSytle}">
               <Image
                    Aspect="AspectFit"
                    Source="{Binding Icon}"/>
          </pancakeview:PancakeView>
          <Label 
               Grid.Column="1"
               Text="{Binding Name}"
               Style="{StaticResource ExpanderTitleTextStyle}"/>
     </Grid>
</Expander.Header>

Definimos la imagen de la categoría junto al texto de la misma. Ahora pasamos al contenido.

<StackLayout 
     BindableLayout.ItemsSource="{Binding Items}">

Usaremos de nuevo BindableLayouts para definir cada listado correspondiente a una categoría.

El indicador de cada categoría

¿Te has fijado en la animación del borde que rodea al icono de una categoría al expandir y contraer?. Para conseguir el resultado vamos a combinar:

  • La propia animación de expandir y contraer de Expander.
  • Cambiaremos la forma del borde usando DataTriggers.
<pancakeview:PancakeView.Triggers>
     <DataTrigger
          TargetType="pancakeview:PancakeView" Binding="{Binding IsDetailVisible}" Value="True">
          <Setter Property="Style" Value="{StaticResource ExpandedColorSytle}" />
     </DataTrigger>
     <DataTrigger
          TargetType="pancakeview:PancakeView" Binding="{Binding IsDetailVisible}" Value="False">
          <Setter Property="Style" Value="{StaticResource CollpasedColorSytle}" />
     </DataTrigger>
</pancakeview:PancakeView.Triggers>

De forma sencilla, aplicamos diferentes estilos basándonos en el estado del Expander. Al estar expandido, la cabecerá mostrará el icono rodeado por un borde que se unirá con otro borde que tendremos en los detalles (Contenido) del expander.

¿El resultado?.

ShoppingList

Puedes encontrar el código en GitHub:

Ver GitHub¿Qué te parece el control Expander?, ¿echas en falta algo?. Personalmente creo que Expander cubre unas necesidades concretas pero que se ven en cierta medidas en Apps. Me agrada ver como se incrementan el conjunto de posibilidades ofrecidas directamente por Xamarin.Forms sin necesidad de plugins.

Recuerda, cualquier tipo de feedback es bienvenido en los comentarios de la entrada.

Más información