En el post anterior, aprendimos a modificar características nativas de un control de Xamarin Forms, cambiando el color y el texto de un Switch en su Renderer.

En el Renderer de cada plataforma, le asignamos diferentes colores, y en el caso de Android, le asignamos los textos para cuando el Switch está encendido o apagado. Pero si lo que queremos es controlar los valores de esas características nativas desde nuestro proyecto portable, ya sea en XAML o en C#, debemos crear un control personalizado, en este caso que herede de Switch, y crear las propiedades respectivas para cambiar esos valores.

En el proyecto portable

Creamos una clase que herede de Switch. Yo la llamaré ExtendedSwitch. En ella creamos las propiedades que usaremos para cambiar las nativas de los controles. Para los que usan el patrón MVVM, las propiedades pueden ser usadas como enlace de datos (Bindings), pero para este ejemplo, las cambiaremos en tiempo de ejecución por code-behind, que es un poco más fácil de entender para los que no están familiarizados con MVVM.

Las propiedades las llamaré:

OnColor, para el color del fondo en iOS y Windows Phone.
ThumbColor, para el color del Thumb en iOS y Android.

[code language=”csharp” title=”ExtendedSwitch.cs”]
public class ExtendedSwitch : Switch
{
public static readonly BindableProperty OnColorProperty =
BindableProperty.Create<ExtendedSwitch, Color>(o => o.OnColor, default(Color));

public Color OnColor
{
get { return (Color)GetValue(OnColorProperty); }
set { SetValue(OnColorProperty, value); }
}

public static readonly BindableProperty ThumbColorProperty =
BindableProperty.Create<ExtendedSwitch, Color>(o => o.ThumbColor, default(Color));

public Color ThumbColor
{
get { return (Color)GetValue(ThumbColorProperty); }
set { SetValue(ThumbColorProperty, value); }
}
}
[/code]

Y para usar este control personalizado desde el XAML, agregamos el namespace y ya podemos crearlo y asignarle valores desde ahí:

[code language=”xml” title=”MainPage.xaml” highlight=”4,22,25,26″]
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:RenderersXAML.Controls;assembly=RenderersXAML"
x:Class="RenderersXAML.MainPage">
<StackLayout
Padding="20">
<Label
Text="OnColor (iOS y Windows Phone)" />
<Entry
x:Name="txtOnColor"
Text="046FA0" />
<Label
Text="ThumbColor (iOS y Android)" />
<Entry
x:Name="txtThumbColor"
Text="803F90" />
<Button
x:Name="btnUpdate"
Clicked="Update"
Text="Actualizar" />
<controls:ExtendedSwitch
x:Name="extendedSwitch"
HorizontalOptions="Center"
OnColor="046FA0"
ThumbColor="803F90" />
</StackLayout>
</ContentPage>
[/code]

[code language=”csharp” title=”MainPage.xaml.cs”]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}

void Update(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtOnColor.Text))
extendedSwitch.OnColor = Color.FromHex(txtOnColor.Text);

if (!string.IsNullOrEmpty(txtThumbColor.Text))
extendedSwitch.ThumbColor = Color.FromHex(txtThumbColor.Text);
}
}
[/code]

En las plataformas

En cada uno de los proyectos de las plataformas, creamos los renderers y el primer parámetro del atributo ExportRenderer sería de tipo ExtendedSwitch.

[code language=”csharp”]
[assembly: ExportRenderer(typeof(ExtendedSwitch), typeof(ExtendedSwitchRenderer))]
[/code]

Es recomendable que antes de hacer uso de las propiedades Control y Element, verifiquemos que sus valores no sean nulos.

Para los que usan el patrón MVVM, los renderer pueden sobrescribir el método OnElementPropertyChanged para notificar los cambios en las propiedades.

Veamos como quedan los renderers en cada plataforma:

iOS

[code language=”csharp” title=”ExtendedSwitchRenderer.cs – iOS”]
public class ExtendedSwitchRenderer : SwitchRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);

SetOnColor();
SetThumbColor();
}

private void SetOnColor()
{
var element = (ExtendedSwitch)Element;

if (element != null && Control != null)
{
if (element.OnColor != Xamarin.Forms.Color.Default)
{
Control.OnTintColor = element.OnColor.ToUIColor();
}
}
}

private void SetThumbColor()
{
var element = (ExtendedSwitch)Element;

if (element != null && Control != null)
{
if (element.ThumbColor != Xamarin.Forms.Color.Default)
{
Control.ThumbTintColor = element.ThumbColor.ToUIColor();
}
}
}

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == ExtendedSwitch.OnColorProperty.PropertyName)
SetOnColor();

if (e.PropertyName == ExtendedSwitch.ThumbColorProperty.PropertyName)
SetThumbColor();
}
}
[/code]

Renderers XAML iOS

Windows Phone

[code language=”csharp” title=”ExtendedSwitchRenderer.cs – Windows Phone”]
public class ExtendedSwitchRenderer : SwitchRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);

SetOnColor();
}

private void SetOnColor()
{
var element = (ExtendedSwitch)Element;

if (element != null && Control != null)
{
var toggle = (ToggleSwitchButton)Control.Child;

if (element.OnColor != Xamarin.Forms.Color.Default)
{
var onColor = element.OnColor;

var wpColor = System.Windows.Media.Color.FromArgb(
(byte)(onColor.A * 255),
(byte)(onColor.R * 255),
(byte)(onColor.G * 255),
(byte)(onColor.B * 255));

toggle.SwitchForeground = new SolidColorBrush(wpColor);
}
}
}

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == ExtendedSwitch.OnColorProperty.PropertyName)
SetOnColor();
}
}
[/code]

Renderers XAML Windows Phone

Android

[code language=”csharp” title=”ExtendedSwitchRenderer.cs – Android”]
public class ExtendedSwitchRenderer : SwitchRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);

SetThumbColor();
}

private void SetThumbColor()
{
var element = (ExtendedSwitch)Element;

if (element != null && Control != null)
{
if (element.ThumbColor != Color.Default)
{
Control.ThumbDrawable = new ColorDrawable(element.ThumbColor.ToAndroid());
}
}
}

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == ExtendedSwitch.ThumbColorProperty.PropertyName)
SetThumbColor();
}
}
[/code]

Renderers XAML Android

Para probar que los colores cambien en tiempo de ejecución, escribimos nuevos valores en los campos y presionamos Actualizar.

Aquí pueden ver el código fuente:

GitHub Source Code