SlideShare una empresa de Scribd logo
Creando controles para
Xamarin.Forms
ORGANIZATION
PLATINUM SPONSORS
Thank you!
COLLABORATORS
@jsuarezruiz
jsuarez@microsoft.com
Mi nombre es Javier, trabajo en Microsoft en el equipo de desarrollo de
Xamarin.Forms y .NET MAUI. Apasionado de la comunidad, participo
activamente en charlas y otros formatos además de coordinar algunos
grupos de usuarios.
Javier Suarez
Software Engineer at Microsoft
¿Qué vamos a ver?
1. Creando controles usando Custom Renderers.
2. Creando controles usando SkiaSharp.
3. Creando Custom Controls.
4. Creando Templated Controls.
5. Trucos y consejos para crear controles.
6. Aspectos a tener en cuenta (rendimiento, etc.).
7. Preguntas & Respuestas.
Creando controles
usando Custom
Renderers
Xamarin.Forms utiliza abstracciones
para definir los elementos.
Posteriormente se transforma cada
abstracción ofreciendo una
implementación y mecanismos en cada
plataforma.
Abstracciones
Extendiendo un control en una plataforma
Personalizando la forma en la que renderizamos un control
Si no nos gusta como se renderiza un control en una plataforma,
podemos cambiarlo
Element describe la apariencia del
control
Button
Text
TextColor
…
Renderer crea una visualización
específica para cada plataforma
ButtonRenderer
ButtonRenderer
ButtonRenderer
UIButton
Button
Button
MyButtonRenderer
UIImage
Creando nuevos controles usando Renderers
Pasos a seguir
Siempre tendremos DOS PARTES: El Elemento y el Renderer
Element describe la apariencia del
control
Button
Text
TextColor
…
Renderer crea una visualización
específica para cada plataforma
ButtonRenderer
ButtonRenderer
ButtonRenderer
Button
Button
MyButtonRenderer UIImage
Creando nuevos controles usando Renderers
Pasos a seguir
1º Paso – Crear la definición en la librería compartida
public class RoundedBoxView : BoxView
{
}
BoxView es una vista existente que
estamos extendiendo. Podríamos
utilizer View y crear una totalmente
nueva.
Creando nuevos controles usando Renderers
Pasos a seguir
2º Paso – Añadir propiedades a nuestra definición
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create<RoundedBoxView, double>(p => p.CornerRadius,
0);
public double CornerRadius
{
get { return (double)base.GetValue(CornerRadiusProperty); }
set { base.SetValue(CornerRadiusProperty, value); }
}
Creando nuevos controles usando Renderers
Pasos a seguir
3º Paso – Implementar un renderer por cada plataforma
public class RoundedBoxViewRenderer : ViewRenderer<RoundedBoxView,
UIView>
{
}
Define el control que estamos
renderizando
Creando nuevos controles usando Renderers
Pasos a seguir
3º Paso – Implementar un renderer por cada plataforma
protected override void OnElementChanged(ElementChangedEventArgs<RoundedBoxView>
e)
{
base.OnElementChanged(e);
var rbv = e.NewElement;
if (rbv != null)
{
var shadowView = new UIView();
_childView = new UIView();
…
SetNativeControl(shadowView);
}
Creando nuevos controles usando Renderers
Pasos a seguir
4º Paso – Registro de librería por plataforma
[assembly: ExportRendererAttribute(typeof(RoundedBoxView),
typeof(RoundedBoxViewRenderer))]
Nuestro custom render
Elemento Xamarin.Forms
Creando nuevos controles usando Renderers
Pasos a seguir
5º Paso – Utilizar el nuevo Control.
xmlns:custom="clr-
namespace:dotnet2020.CustomControls;assembly=dotnet2020"
<custom:RoundedBoxView
x:Name="rbv"
WidthRequest="200"
HeightRequest="200"
Stroke="Yellow"
StrokeThickness="2"
CornerRadius="20"
Color="Red" />
A tener en cuenta
Cuando un Custom Renderer comienza su ejecución, el primer método que se lanza es OnElementChanged. En
este método es donde puede acceder a las propiedades y realizar cualquier personalización.
Tenga en cuenta que este método consume un parámetro importante llamado ElementChangedEventArgs con
dos propiedades.
• NewElement
• OldElement
NewElement contiene una referencia al control de Xamarin Forms. OldElement contiene una referencia al
Custom Renderer al que se adjuntó el control de Xamarin Forms. Es importante prestar atención a las dos
propiedades al suscribirse y darse de baja de eventos para evitar fugas de memoria.
A tener en cuenta
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
// Subscribe for events
e.NewElement.SizeChanged += XFButtonOnSizeChanged;
}
else if (e.OldElement != null)
{
// Unsubscribe from events
e.OldElement.SizeChanged -= XFButtonOnSizeChanged;
}
}
A tener en cuenta
Al crear el Custom Renderer podemos sobrecargar el método Dispose. Este método se
ejecutará al liberar el control usado (por ejemplo, al navegar atrás y liberar los recursos
de la página). Si creas recursos en el Renderer como por ejemplo Drawables, recuerda
liberar los recursos.
protected override void Dispose(bool disposing)
{
if (Control != null)
{
Control.CheckedChanged -= OnControlCheckedChanged;
}
base.Dispose(disposing);
}
A tener en cuenta
En las primeras versiones de Xamarin.Forms todos los Custom Renderers hacían uso de
ViewRenderer.
ViewRenderer crea una instancia del control nativo envuelto en un contenedor que se
encargará de realizar tareas auxiliares como posicionamiento.
Con el tiempo llegaron los Fast Renderers. El objetivo de este tipo de renderers es el de
evitar crear el contenedor auxiliar reduciendo el volumen de la jerarquía y aumentando
el rendimiento. Para crear un Fast Renderer se debe implementar la interfaz
IVisualElementRenderer.
Pros y contras
Pros
• Obtenemos un rendimiento muy alto (control nativo).
• Podemos permitir extender (Effects, Platform Specific, etc.) aprovechando la
capacidad y posibilidades del código nativo.
Contras
• Requiere mayor cantidad de código.
• Requiere conocimientos de desarrollo nativo en cada plataforma.
• Extender requiere también conocimientos de desarrollo nativo.
Creando controles
usando SkiaSharp
SkiaSharp
Librería de gráficos 2D.
Usada por Google en Chrome, Android o Flutter.
Cross platform: Android, iOS, Mac, Windows, etc.
Composited rendering mode
Aceleración por GPU Efectos y shaders
personalizados
Tanto Skia como los bindings de SkiaSharp se
encuentran en Desarrollo activo.
Usar SkiaSharp: Añadir la librería
Para usar SkiaSharp en Xamarin.Forms necesitamos añadir el paquete NuGet
SkiaSharp.Views.Forms.
La librería proporciona dos vistas que puede usar como base para crear controles:
SKCanvasView y SKGLView.
CanvasView usa la CPU mientras que GLView usa OpenGL y, por lo tanto, la GPU. Puedes
pensar intuitivamente que usar la GPU para operaciones gráficas es siempre la mejor
opción, pero, de hecho, OpenGL tiene una gran sobrecarga al crear el contexto GL.
CanvasView simplemente asigna la memoria que necesita y siempre que haya suficiente
potencia de CPU disponible, puede renderizar sin problemas
Usar SkiaSharp: El Canvas
Para comenzar a dibujar, basta con usar al método OnPaintSurface. Podemos hacerlo al
subscribirnos al evento PaintSurface o sobrecargando directamente el método
OnPaintSurface.
public class SkiaControl : SKCanvasView
{
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
}
}
Usar SkiaSharp: Dibujando
Para dibujar algo, podemos añadir directamente un punto, línea, rectángulo, círculo,
rectángulo redondeado, texto o imagen al canvas. La posición de cada forma está
definida por SKPoints o SKRects.
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
// Circle
canvas.DrawCircle(bounds.Width/4, bounds.MidY, radius,
orangePaint);
}
Usar SkiaSharp: Paint
Todas las operaciones de dibujado en el Canvas requieren un Paint para definir la forma
que se dibuja.
var colorPaint = new SKPaint
{
Color = Color.Red.ToSKColor(),
StrokeWidth = 5,
Style = SKPaintStyle.Stroke,
IsAntialias = true
};
Usar SkiaSharp: Manipular el Canvas
En lugar de transformar cada shape, puede ser más sencillo (y menos costoso)
transformar el Canvas en sí. Un ejemplo claro es usar el método ClipPath que enmascara
el área dibujable. Otros métodos muy útiles son Transform (mover en x, y), Scale o
Rotate.
Al aplicar una transformación, se aplicará a todos los dibujos posteriores. Para restaurar
la transformación de lienzo original, se puede usar Save y Restore.
canvas.RotateDegrees(-90, centeredRect.MidX, centeredRect.MidY);
Usar SkiaSharp: User Input
Los controles normalmente reciben alguna entrada del usuario. Para que nuestro control sea interactivo,
podemos usar los gestos de Xamarin.Forms, gestos nativos o el evento Touch de SkiaSharp.
Tan solo debemos establecer la propiedad EnableTouchEvent en true y usar al método OnTouch.
protected override void OnTouch(SKTouchEventArgs e)
{
if (e.ActionType == SKTouchAction.Entered
|| e.ActionType == SKTouchAction.Pressed
|| e.ActionType == SKTouchAction.Moved)
{
_touchPoint = e.Location;
InvalidateSurface();
}
e.Handled = true;
}
Crear controles con SkiaSharp
Haremos uso principalmente de un Canvas donde dibujaremos la
mayor parte del control. SkiaSharp como hemos visto, también
nos permite la gestión de la interacción del usuario, etc.
Para permitir la personalización nos basamos en el uso de
BindableProperties.
A tener en cuenta
Para obtener el mejor rendimiento posible:
1. Evita usar múltiples Canvas y realiza el dibujado en la medida de lo
posible en un único Canvas.
2. Reutiliza objetos SKPaint, SKTypeFace, etc. siempre que sea posible.
3. Hay diferentes formas de conseguir el mismo resultado. Puedes
realizar toda la opetación de dibujado y devolver un SKBitmap
directamente.
4. A la hora de crear controles, puedes usar un SKCanvasView como
elemento base en lugar de un ContentView si no necesitas
componer (añadir otros elementos) además del Canvas.
Pros y contras
Pros
• Dibujando directamente en un Canvas e incluso con posibilidad de usar GPU,
rendimiento muy alto.
• Definir el control una única vez para todas las plataformas.
Contras
• “No estamos usando APIs nativas, ni elementos nativos; estamos dibujando en un
lienzo”.
• Es necesario añadir dependencias con SkiaSharp con el aumento de tamaño (aprox.
>5MB).
• Requiere conocer las APIs de SkiaSharp.
Creando controles
personalizados
Crear controles personalizados
ContentView es un tipo de Layout que contiene un único
elemento secundario y se utiliza normalmente para crear
controles personalizados y reutilizables.
El proceso para crear un control personalizado es:
1. Crear una nueva clase que herede de ContentView.
2. Definir propiedades (BindableProperty) o eventos.
3. Crear la interfaz de usuario.
¡Más posibilidades!
•Esta forma de crear controles existe desde el inicio en
Xamarin.Forms. Sin embargo, desde las últimas versiones las
posibilidades se han incrementado. La llegada de APIs como:
•Brushes
•Shapes
•AppTheme
•Etc
•Permiten resultados anteriormente no posibles sin un Custom
Renderer o SkiaSharp.
A tener en cuenta
Para obtener el mejor rendimiento posible:
1. Ten un control exhaustivo de la jerarquía a crear con el control.
A mayor jerarquía, mayor será el impacto negativo en el
rendimiento.
2. Crear controles que implementen IDisposable, y recuerda
liberar recursos.
Pros y contras
Pros
• Sencillo de crear. No requiere conocimientos específicos de plataforma, todo se crea
usando la abstracción de Xamarin.Forms.
• Definir el control una única vez para todas las plataformas.
Contras
• Si para definir un control, lo creamos vía composición usando 5 vistas de
Xamarin.Forms, se requiere instanciar esas 5 vistas con un impacto en el rendimiento.
Creando Templated
Controls
¿Permitir personalizar todo?
Con una buena especificación para un control, creando
propiedades, eventos, etc. podemos cubrir la mayoría de las
necesidades, pero sería imposible cubrir todos los casos.
Pongamos un ejemplo. En nuestro CheckBox, podemos añadir
una propiedad para personalizar el color del borde pero, ¿y si
alguien quiere el borde punteado?. De acuerdo, podemos añadir
otra propiedad, pero, ¿y si alguien necesita…?.
ControlTemplate
La plantilla de control o ControlTemplate de Xamarin.Forms
permiten definir la estructura visual del control.
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle
x:Name="PART_Background"
Stroke="{TemplateBinding Color}"/>
<Path
x:Name="PART_Glyph"
Data="M30.561941,0L31.997,1.393004 10.467954,23.597999 0,15.350999 1.2379759,13.780992 10.287961,20.909952z"
Stroke="White"/>
<ContentPresenter
x:Name="PART_Content"
Content="{TemplateBinding Content}"
Grid.Column="1"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
</ControlTemplate>
Más posibilidades
La llegada a Xamarin.Forms de APIs de Brushes y Shapes permiten
dibujar y “colorear” prácticamente lo que necesitemos
aumentando las posibilidades de crear controles.
Piensa un poco, ¿Cómo compondrías un Slider?. Es una línea, con una elipse que
podemos mover.
¿Y un CheckBox?. Al final es un rectángulo para dibujar el fondo junto con un
indicador de marcado.
Templated Control
El elemento llamado ContentPresenter, que a menudo se usa
dentro de las plantillas de control, es un elemento que permite
insertar contenido en tiempo de ejecución.
Por otro lado, la extensión de marcado TemplateBinding enlaza
una propiedad de un elemento que se encuentra en una clase
ControlTemplate a una propiedad pública definida por el control
personalizado.
Templated Control
Una vez que se crearon las instancias de una plantilla de control,
se llama al método OnApplyTemplate de la plantilla.
En este método podemos usar el método GetTemplateChild para
acceder a las views que componen el control.
A tener en cuenta
Para obtener el mejor rendimiento posible:
1. Normalmente se accede a los elementos de la plantilla de
control para operaciones genéricas relacionadas con asignar
tamaños, posiciones o propiedades básicas como colores. Usa
elementos base. De esta forma, si se modifica la plantilla no
tiene impacto.
2. No accedas a elementos de la plantilla si no vas a utilizarlos.
3. Crear controles que implementen IDisposable, y recuerda
liberar recursos.
Pros y contras
Pros
• Sencillo de crear. No requiere conocimientos específicos de plataforma, todo se crea
usando la abstracción de Xamarin.Forms.
• Definir el control una única vez para todas las plataformas.
• ¡Permite no solo personalizar el control vía propiedades, sino acceder a la plantilla y
modificar cualquier cosa!.
Contras
• Si para definir un control, lo creamos vía composición usando 5 vistas de
Xamarin.Forms, se requiere instanciar esas 5 vistas con un impacto en el rendimiento.
Otros factores a tener
en cuenta
A tener en cuenta
• El rendimiento en Custom Renderers
es el que obtenemos con código
nativo, y como general, muy alto.
• Dependiendo de la complejidad del
control nativo (elementos a instanciar,
dependencias, etc.) es posible
conseguir resultados similares o
mejores con SkiaSharp.
• El rendimiento de Custom Controls y
Templated Controls radica en la
complejidad de la jerarquía visual
necesaria para crear el control.
Rendimiento similar. Si es posible,
permitir el uso de plantilla de control.
Preguntas &
Respuestas
Thanks and …
See you soon!
Thanks also to the sponsors.
Without whom this would not have been posible.

Más contenido relacionado

PPTX
DotNet2018: Xamarin.Forms Everywhere!
PPTX
Monkey Conf 2020: .NET MAUI Handlers
PPTX
Taller Xamarin Monkey Conf 2018
PPTX
Analizando interfaces de usuario avanzadas con Xamarin.Forms
PPTX
dotNetMálaga 2017 - Trucos y consejos rendimiento Xamarin.Forms
PPTX
DotNet 2019: Optimizando Apps con Xamarin.Forms
PPTX
Monkey Conf 2018: Conociendo Xamarin.Forms Shell
PPTX
.Net Conf Sevilla 2018
DotNet2018: Xamarin.Forms Everywhere!
Monkey Conf 2020: .NET MAUI Handlers
Taller Xamarin Monkey Conf 2018
Analizando interfaces de usuario avanzadas con Xamarin.Forms
dotNetMálaga 2017 - Trucos y consejos rendimiento Xamarin.Forms
DotNet 2019: Optimizando Apps con Xamarin.Forms
Monkey Conf 2018: Conociendo Xamarin.Forms Shell
.Net Conf Sevilla 2018

La actualidad más candente (20)

PPTX
OpenSouthCode 2018: Taller Xamarin
PPTX
DotNetDom: El futuro de Xamarin
PPTX
SVQXDG - Introducción a Embeddinator-4000
PPTX
WinObjC: Windows Bridge para iOS
PPTX
Extendiendo Xamarin.Forms
PPTX
Introducción a Xamarin
PPTX
Windows 10: Hel10 World! - Novedades XAML
PPTX
Tech Club Asturias: Un vistazo al presente y futuro de Xamarin.Forms
PPTX
Trucos y consejos rendimiento Xamarin.Forms
PPTX
Servicios Xamarin
PPTX
Integración Continua con Apps Xamarin
PDF
Arquitectura xamarin - Nuestra primera app
PPTX
Aumento de productividad, herramientas Xamarin
PPTX
Reconnect(); Sevilla - Introducción a Xamarin 4
PPTX
Xamarin Dev Days Málaga 2017 - Apps conectadas con Azure
PPTX
Introduction to xamarin
PPTX
Crear Apps móviles multiplataforma con Xamarin compartiendo la mayor cantidad...
PPTX
Xamarin REvolve 2016
PPTX
Crear Apps Multiplataforma compartiendo la mayor cantidad con Xamarin
PPTX
Introducción a Xamarin.Forms
OpenSouthCode 2018: Taller Xamarin
DotNetDom: El futuro de Xamarin
SVQXDG - Introducción a Embeddinator-4000
WinObjC: Windows Bridge para iOS
Extendiendo Xamarin.Forms
Introducción a Xamarin
Windows 10: Hel10 World! - Novedades XAML
Tech Club Asturias: Un vistazo al presente y futuro de Xamarin.Forms
Trucos y consejos rendimiento Xamarin.Forms
Servicios Xamarin
Integración Continua con Apps Xamarin
Arquitectura xamarin - Nuestra primera app
Aumento de productividad, herramientas Xamarin
Reconnect(); Sevilla - Introducción a Xamarin 4
Xamarin Dev Days Málaga 2017 - Apps conectadas con Azure
Introduction to xamarin
Crear Apps móviles multiplataforma con Xamarin compartiendo la mayor cantidad...
Xamarin REvolve 2016
Crear Apps Multiplataforma compartiendo la mayor cantidad con Xamarin
Introducción a Xamarin.Forms
Publicidad

Similar a Creando controles para Xamarin.Forms (20)

PDF
Custom Renders Xamarin.Forms
PDF
Topicos Selectos de Xamarin
PPTX
DevNights Xamarin: Custom Renderers
PPTX
Custom Renderers Made Simple
PPTX
Extendiendo Xamarin.Forms con Custom Renders
PPTX
Effects & Custom Renderers en Xamarin.Forms
PPTX
Monkey Conf 2019: Presente y futuro de Xamarin.Forms
PPTX
Explorando los controles de Xamarin.Forms
PPTX
DotNet 2019 | Javier Suarez - Optimizando Apps con Xamarin Forms
PDF
Getting started with xamarin forms
PPTX
Novedades Xamarin.Forms 2
PPTX
Evento Bolivia - Fundamentos de Xamarin - Desarrollo de apps moviles multipla...
PPTX
Xamarin Dev Days Madrid - Xamarin.Forms
PPTX
Intro to xamarin forms: converters, animations, behaviors and triggers
PDF
App inventor
PPTX
Semana Lambda - Fundamentos de Xamarin - Desarrollo de apps moviles multiplat...
PPTX
Net latino
PPTX
Women Who Code Bogota: Introduction to Xamarin Forms
PPTX
.NET Day Guatemala
Custom Renders Xamarin.Forms
Topicos Selectos de Xamarin
DevNights Xamarin: Custom Renderers
Custom Renderers Made Simple
Extendiendo Xamarin.Forms con Custom Renders
Effects & Custom Renderers en Xamarin.Forms
Monkey Conf 2019: Presente y futuro de Xamarin.Forms
Explorando los controles de Xamarin.Forms
DotNet 2019 | Javier Suarez - Optimizando Apps con Xamarin Forms
Getting started with xamarin forms
Novedades Xamarin.Forms 2
Evento Bolivia - Fundamentos de Xamarin - Desarrollo de apps moviles multipla...
Xamarin Dev Days Madrid - Xamarin.Forms
Intro to xamarin forms: converters, animations, behaviors and triggers
App inventor
Semana Lambda - Fundamentos de Xamarin - Desarrollo de apps moviles multiplat...
Net latino
Women Who Code Bogota: Introduction to Xamarin Forms
.NET Day Guatemala
Publicidad

Más de Javier Suárez Ruiz (15)

PPTX
Cape Town MS Developer User Group: Xamarin Community Toolkit
PPTX
Monkey Conf 2020: Xamarin Community Toolkit: More possibilities with Xamarin....
PPTX
Crear interfaces de usuario atractivas con Xamarin.Forms
PPTX
#XamarinUIJuly Summary
PPTX
Novedades Xamarin 3.0 Preview
PPTX
Desarrollo Xamarin, más allá del desarrollo
PPTX
Introducción a Xamarin.Forms
PPTX
Introducción a Xamarin
PPTX
Plain Concepts Tech Day: Desarrollo de aplicaciones multiplataforma con Xamarin
PPTX
Novedades Xamarin Connect(); 2017
PPTX
Codemotion 2017 - Taller Xamarin
PPTX
dotNetMálaga 2017 - Taller Hololens con Wave Engine
PPTX
Embeddinator-4000
PPTX
Xamarin Hol - Módulo V: Mobile DevOps con Visual Studio Team Services y Hocke...
PPTX
Xamarin Dev Days Madrid 2017 - Xamarin.Forms
Cape Town MS Developer User Group: Xamarin Community Toolkit
Monkey Conf 2020: Xamarin Community Toolkit: More possibilities with Xamarin....
Crear interfaces de usuario atractivas con Xamarin.Forms
#XamarinUIJuly Summary
Novedades Xamarin 3.0 Preview
Desarrollo Xamarin, más allá del desarrollo
Introducción a Xamarin.Forms
Introducción a Xamarin
Plain Concepts Tech Day: Desarrollo de aplicaciones multiplataforma con Xamarin
Novedades Xamarin Connect(); 2017
Codemotion 2017 - Taller Xamarin
dotNetMálaga 2017 - Taller Hololens con Wave Engine
Embeddinator-4000
Xamarin Hol - Módulo V: Mobile DevOps con Visual Studio Team Services y Hocke...
Xamarin Dev Days Madrid 2017 - Xamarin.Forms

Último (8)

DOCX
trabajo programacion.docxxdxxxddxdxxdxdxxxdxxdxdxd
PDF
simulacion de teoria de control para maquinas
PDF
modelos de control para sistemas digitales
PPTX
Derechos_de_Autor_y_Creative_Commons.pptx
PDF
DIMENSIONADO DE UNA INSTALACION FOTOVOLTAICA.pdf
PDF
AutoCAD Herramientas para el futuro, Juan Fandiño
PPTX
sistemas de informacion.................
PDF
Su punto de partida en la IA: Microsoft 365 Copilot Chat
trabajo programacion.docxxdxxxddxdxxdxdxxxdxxdxdxd
simulacion de teoria de control para maquinas
modelos de control para sistemas digitales
Derechos_de_Autor_y_Creative_Commons.pptx
DIMENSIONADO DE UNA INSTALACION FOTOVOLTAICA.pdf
AutoCAD Herramientas para el futuro, Juan Fandiño
sistemas de informacion.................
Su punto de partida en la IA: Microsoft 365 Copilot Chat

Creando controles para Xamarin.Forms

  • 3. @jsuarezruiz jsuarez@microsoft.com Mi nombre es Javier, trabajo en Microsoft en el equipo de desarrollo de Xamarin.Forms y .NET MAUI. Apasionado de la comunidad, participo activamente en charlas y otros formatos además de coordinar algunos grupos de usuarios. Javier Suarez Software Engineer at Microsoft
  • 4. ¿Qué vamos a ver? 1. Creando controles usando Custom Renderers. 2. Creando controles usando SkiaSharp. 3. Creando Custom Controls. 4. Creando Templated Controls. 5. Trucos y consejos para crear controles. 6. Aspectos a tener en cuenta (rendimiento, etc.). 7. Preguntas & Respuestas.
  • 6. Xamarin.Forms utiliza abstracciones para definir los elementos. Posteriormente se transforma cada abstracción ofreciendo una implementación y mecanismos en cada plataforma. Abstracciones
  • 7. Extendiendo un control en una plataforma Personalizando la forma en la que renderizamos un control Si no nos gusta como se renderiza un control en una plataforma, podemos cambiarlo Element describe la apariencia del control Button Text TextColor … Renderer crea una visualización específica para cada plataforma ButtonRenderer ButtonRenderer ButtonRenderer UIButton Button Button MyButtonRenderer UIImage
  • 8. Creando nuevos controles usando Renderers Pasos a seguir Siempre tendremos DOS PARTES: El Elemento y el Renderer Element describe la apariencia del control Button Text TextColor … Renderer crea una visualización específica para cada plataforma ButtonRenderer ButtonRenderer ButtonRenderer Button Button MyButtonRenderer UIImage
  • 9. Creando nuevos controles usando Renderers Pasos a seguir 1º Paso – Crear la definición en la librería compartida public class RoundedBoxView : BoxView { } BoxView es una vista existente que estamos extendiendo. Podríamos utilizer View y crear una totalmente nueva.
  • 10. Creando nuevos controles usando Renderers Pasos a seguir 2º Paso – Añadir propiedades a nuestra definición public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create<RoundedBoxView, double>(p => p.CornerRadius, 0); public double CornerRadius { get { return (double)base.GetValue(CornerRadiusProperty); } set { base.SetValue(CornerRadiusProperty, value); } }
  • 11. Creando nuevos controles usando Renderers Pasos a seguir 3º Paso – Implementar un renderer por cada plataforma public class RoundedBoxViewRenderer : ViewRenderer<RoundedBoxView, UIView> { } Define el control que estamos renderizando
  • 12. Creando nuevos controles usando Renderers Pasos a seguir 3º Paso – Implementar un renderer por cada plataforma protected override void OnElementChanged(ElementChangedEventArgs<RoundedBoxView> e) { base.OnElementChanged(e); var rbv = e.NewElement; if (rbv != null) { var shadowView = new UIView(); _childView = new UIView(); … SetNativeControl(shadowView); }
  • 13. Creando nuevos controles usando Renderers Pasos a seguir 4º Paso – Registro de librería por plataforma [assembly: ExportRendererAttribute(typeof(RoundedBoxView), typeof(RoundedBoxViewRenderer))] Nuestro custom render Elemento Xamarin.Forms
  • 14. Creando nuevos controles usando Renderers Pasos a seguir 5º Paso – Utilizar el nuevo Control. xmlns:custom="clr- namespace:dotnet2020.CustomControls;assembly=dotnet2020" <custom:RoundedBoxView x:Name="rbv" WidthRequest="200" HeightRequest="200" Stroke="Yellow" StrokeThickness="2" CornerRadius="20" Color="Red" />
  • 15. A tener en cuenta Cuando un Custom Renderer comienza su ejecución, el primer método que se lanza es OnElementChanged. En este método es donde puede acceder a las propiedades y realizar cualquier personalización. Tenga en cuenta que este método consume un parámetro importante llamado ElementChangedEventArgs con dos propiedades. • NewElement • OldElement NewElement contiene una referencia al control de Xamarin Forms. OldElement contiene una referencia al Custom Renderer al que se adjuntó el control de Xamarin Forms. Es importante prestar atención a las dos propiedades al suscribirse y darse de baja de eventos para evitar fugas de memoria.
  • 16. A tener en cuenta protected override void OnElementChanged(ElementChangedEventArgs<Button> e) { base.OnElementChanged(e); if (e.NewElement != null) { // Subscribe for events e.NewElement.SizeChanged += XFButtonOnSizeChanged; } else if (e.OldElement != null) { // Unsubscribe from events e.OldElement.SizeChanged -= XFButtonOnSizeChanged; } }
  • 17. A tener en cuenta Al crear el Custom Renderer podemos sobrecargar el método Dispose. Este método se ejecutará al liberar el control usado (por ejemplo, al navegar atrás y liberar los recursos de la página). Si creas recursos en el Renderer como por ejemplo Drawables, recuerda liberar los recursos. protected override void Dispose(bool disposing) { if (Control != null) { Control.CheckedChanged -= OnControlCheckedChanged; } base.Dispose(disposing); }
  • 18. A tener en cuenta En las primeras versiones de Xamarin.Forms todos los Custom Renderers hacían uso de ViewRenderer. ViewRenderer crea una instancia del control nativo envuelto en un contenedor que se encargará de realizar tareas auxiliares como posicionamiento. Con el tiempo llegaron los Fast Renderers. El objetivo de este tipo de renderers es el de evitar crear el contenedor auxiliar reduciendo el volumen de la jerarquía y aumentando el rendimiento. Para crear un Fast Renderer se debe implementar la interfaz IVisualElementRenderer.
  • 19. Pros y contras Pros • Obtenemos un rendimiento muy alto (control nativo). • Podemos permitir extender (Effects, Platform Specific, etc.) aprovechando la capacidad y posibilidades del código nativo. Contras • Requiere mayor cantidad de código. • Requiere conocimientos de desarrollo nativo en cada plataforma. • Extender requiere también conocimientos de desarrollo nativo.
  • 21. SkiaSharp Librería de gráficos 2D. Usada por Google en Chrome, Android o Flutter. Cross platform: Android, iOS, Mac, Windows, etc. Composited rendering mode Aceleración por GPU Efectos y shaders personalizados Tanto Skia como los bindings de SkiaSharp se encuentran en Desarrollo activo.
  • 22. Usar SkiaSharp: Añadir la librería Para usar SkiaSharp en Xamarin.Forms necesitamos añadir el paquete NuGet SkiaSharp.Views.Forms. La librería proporciona dos vistas que puede usar como base para crear controles: SKCanvasView y SKGLView. CanvasView usa la CPU mientras que GLView usa OpenGL y, por lo tanto, la GPU. Puedes pensar intuitivamente que usar la GPU para operaciones gráficas es siempre la mejor opción, pero, de hecho, OpenGL tiene una gran sobrecarga al crear el contexto GL. CanvasView simplemente asigna la memoria que necesita y siempre que haya suficiente potencia de CPU disponible, puede renderizar sin problemas
  • 23. Usar SkiaSharp: El Canvas Para comenzar a dibujar, basta con usar al método OnPaintSurface. Podemos hacerlo al subscribirnos al evento PaintSurface o sobrecargando directamente el método OnPaintSurface. public class SkiaControl : SKCanvasView { protected override void OnPaintSurface(SKPaintSurfaceEventArgs e) { var canvas = e.Surface.Canvas; } }
  • 24. Usar SkiaSharp: Dibujando Para dibujar algo, podemos añadir directamente un punto, línea, rectángulo, círculo, rectángulo redondeado, texto o imagen al canvas. La posición de cada forma está definida por SKPoints o SKRects. protected override void OnPaintSurface(SKPaintSurfaceEventArgs e) { var canvas = e.Surface.Canvas; // Circle canvas.DrawCircle(bounds.Width/4, bounds.MidY, radius, orangePaint); }
  • 25. Usar SkiaSharp: Paint Todas las operaciones de dibujado en el Canvas requieren un Paint para definir la forma que se dibuja. var colorPaint = new SKPaint { Color = Color.Red.ToSKColor(), StrokeWidth = 5, Style = SKPaintStyle.Stroke, IsAntialias = true };
  • 26. Usar SkiaSharp: Manipular el Canvas En lugar de transformar cada shape, puede ser más sencillo (y menos costoso) transformar el Canvas en sí. Un ejemplo claro es usar el método ClipPath que enmascara el área dibujable. Otros métodos muy útiles son Transform (mover en x, y), Scale o Rotate. Al aplicar una transformación, se aplicará a todos los dibujos posteriores. Para restaurar la transformación de lienzo original, se puede usar Save y Restore. canvas.RotateDegrees(-90, centeredRect.MidX, centeredRect.MidY);
  • 27. Usar SkiaSharp: User Input Los controles normalmente reciben alguna entrada del usuario. Para que nuestro control sea interactivo, podemos usar los gestos de Xamarin.Forms, gestos nativos o el evento Touch de SkiaSharp. Tan solo debemos establecer la propiedad EnableTouchEvent en true y usar al método OnTouch. protected override void OnTouch(SKTouchEventArgs e) { if (e.ActionType == SKTouchAction.Entered || e.ActionType == SKTouchAction.Pressed || e.ActionType == SKTouchAction.Moved) { _touchPoint = e.Location; InvalidateSurface(); } e.Handled = true; }
  • 28. Crear controles con SkiaSharp Haremos uso principalmente de un Canvas donde dibujaremos la mayor parte del control. SkiaSharp como hemos visto, también nos permite la gestión de la interacción del usuario, etc. Para permitir la personalización nos basamos en el uso de BindableProperties.
  • 29. A tener en cuenta Para obtener el mejor rendimiento posible: 1. Evita usar múltiples Canvas y realiza el dibujado en la medida de lo posible en un único Canvas. 2. Reutiliza objetos SKPaint, SKTypeFace, etc. siempre que sea posible. 3. Hay diferentes formas de conseguir el mismo resultado. Puedes realizar toda la opetación de dibujado y devolver un SKBitmap directamente. 4. A la hora de crear controles, puedes usar un SKCanvasView como elemento base en lugar de un ContentView si no necesitas componer (añadir otros elementos) además del Canvas.
  • 30. Pros y contras Pros • Dibujando directamente en un Canvas e incluso con posibilidad de usar GPU, rendimiento muy alto. • Definir el control una única vez para todas las plataformas. Contras • “No estamos usando APIs nativas, ni elementos nativos; estamos dibujando en un lienzo”. • Es necesario añadir dependencias con SkiaSharp con el aumento de tamaño (aprox. >5MB). • Requiere conocer las APIs de SkiaSharp.
  • 32. Crear controles personalizados ContentView es un tipo de Layout que contiene un único elemento secundario y se utiliza normalmente para crear controles personalizados y reutilizables. El proceso para crear un control personalizado es: 1. Crear una nueva clase que herede de ContentView. 2. Definir propiedades (BindableProperty) o eventos. 3. Crear la interfaz de usuario.
  • 33. ¡Más posibilidades! •Esta forma de crear controles existe desde el inicio en Xamarin.Forms. Sin embargo, desde las últimas versiones las posibilidades se han incrementado. La llegada de APIs como: •Brushes •Shapes •AppTheme •Etc •Permiten resultados anteriormente no posibles sin un Custom Renderer o SkiaSharp.
  • 34. A tener en cuenta Para obtener el mejor rendimiento posible: 1. Ten un control exhaustivo de la jerarquía a crear con el control. A mayor jerarquía, mayor será el impacto negativo en el rendimiento. 2. Crear controles que implementen IDisposable, y recuerda liberar recursos.
  • 35. Pros y contras Pros • Sencillo de crear. No requiere conocimientos específicos de plataforma, todo se crea usando la abstracción de Xamarin.Forms. • Definir el control una única vez para todas las plataformas. Contras • Si para definir un control, lo creamos vía composición usando 5 vistas de Xamarin.Forms, se requiere instanciar esas 5 vistas con un impacto en el rendimiento.
  • 37. ¿Permitir personalizar todo? Con una buena especificación para un control, creando propiedades, eventos, etc. podemos cubrir la mayoría de las necesidades, pero sería imposible cubrir todos los casos. Pongamos un ejemplo. En nuestro CheckBox, podemos añadir una propiedad para personalizar el color del borde pero, ¿y si alguien quiere el borde punteado?. De acuerdo, podemos añadir otra propiedad, pero, ¿y si alguien necesita…?.
  • 38. ControlTemplate La plantilla de control o ControlTemplate de Xamarin.Forms permiten definir la estructura visual del control. <ControlTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Rectangle x:Name="PART_Background" Stroke="{TemplateBinding Color}"/> <Path x:Name="PART_Glyph" Data="M30.561941,0L31.997,1.393004 10.467954,23.597999 0,15.350999 1.2379759,13.780992 10.287961,20.909952z" Stroke="White"/> <ContentPresenter x:Name="PART_Content" Content="{TemplateBinding Content}" Grid.Column="1" HorizontalOptions="Center" VerticalOptions="Center"/> </Grid> </ControlTemplate>
  • 39. Más posibilidades La llegada a Xamarin.Forms de APIs de Brushes y Shapes permiten dibujar y “colorear” prácticamente lo que necesitemos aumentando las posibilidades de crear controles. Piensa un poco, ¿Cómo compondrías un Slider?. Es una línea, con una elipse que podemos mover. ¿Y un CheckBox?. Al final es un rectángulo para dibujar el fondo junto con un indicador de marcado.
  • 40. Templated Control El elemento llamado ContentPresenter, que a menudo se usa dentro de las plantillas de control, es un elemento que permite insertar contenido en tiempo de ejecución. Por otro lado, la extensión de marcado TemplateBinding enlaza una propiedad de un elemento que se encuentra en una clase ControlTemplate a una propiedad pública definida por el control personalizado.
  • 41. Templated Control Una vez que se crearon las instancias de una plantilla de control, se llama al método OnApplyTemplate de la plantilla. En este método podemos usar el método GetTemplateChild para acceder a las views que componen el control.
  • 42. A tener en cuenta Para obtener el mejor rendimiento posible: 1. Normalmente se accede a los elementos de la plantilla de control para operaciones genéricas relacionadas con asignar tamaños, posiciones o propiedades básicas como colores. Usa elementos base. De esta forma, si se modifica la plantilla no tiene impacto. 2. No accedas a elementos de la plantilla si no vas a utilizarlos. 3. Crear controles que implementen IDisposable, y recuerda liberar recursos.
  • 43. Pros y contras Pros • Sencillo de crear. No requiere conocimientos específicos de plataforma, todo se crea usando la abstracción de Xamarin.Forms. • Definir el control una única vez para todas las plataformas. • ¡Permite no solo personalizar el control vía propiedades, sino acceder a la plantilla y modificar cualquier cosa!. Contras • Si para definir un control, lo creamos vía composición usando 5 vistas de Xamarin.Forms, se requiere instanciar esas 5 vistas con un impacto en el rendimiento.
  • 44. Otros factores a tener en cuenta
  • 45. A tener en cuenta • El rendimiento en Custom Renderers es el que obtenemos con código nativo, y como general, muy alto. • Dependiendo de la complejidad del control nativo (elementos a instanciar, dependencias, etc.) es posible conseguir resultados similares o mejores con SkiaSharp. • El rendimiento de Custom Controls y Templated Controls radica en la complejidad de la jerarquía visual necesaria para crear el control. Rendimiento similar. Si es posible, permitir el uso de plantilla de control.
  • 47. Thanks and … See you soon! Thanks also to the sponsors. Without whom this would not have been posible.