Xamarin.Forms
Création de contrôles personnalisés
Recherche…
Introduction
Chaque vue Xamarin.Forms
est accompagnée d'un rendu pour chaque plate-forme qui crée une instance d'un contrôle natif. Lorsqu'une vue est rendue sur la plate-forme spécifique, la classe ViewRenderer
est instanciée.
Le processus pour ce faire est le suivant:
Créez un contrôle personnalisé Xamarin.Forms.
Consommez le contrôle personnalisé de Xamarin.Forms.
Créez le moteur de rendu personnalisé pour le contrôle sur chaque plate-forme.
Implémenter un contrôle CheckBox
Dans cet exemple, nous allons implémenter une case à cocher personnalisée pour Android et iOS.
Création du contrôle personnalisé
namespace CheckBoxCustomRendererExample
{
public class Checkbox : View
{
public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create<Checkbox, bool>(p => p.IsChecked, true, propertyChanged: (s, o, n) => { (s as Checkbox).OnChecked(new EventArgs()); });
public static readonly BindableProperty ColorProperty = BindableProperty.Create<Checkbox, Color>(p => p.Color, Color.Default);
public bool IsChecked
{
get
{
return (bool)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
public Color Color
{
get
{
return (Color)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
public event EventHandler Checked;
protected virtual void OnChecked(EventArgs e)
{
if (Checked != null)
Checked(this, e);
}
}
}
Nous commencerons par le moteur de rendu personnalisé Android en créant une nouvelle classe ( CheckboxCustomRenderer
) dans la partie Android
de notre solution.
Quelques détails importants à noter:
- Nous devons marquer le haut de notre classe avec l'attribut ExportRenderer pour que le rendu soit enregistré avec
Xamarin.Forms
. De cette façon,Xamarin.Forms
utilisera ce moteur de rendu lorsqu'ilXamarin.Forms
de créer notre objetCheckbox
surAndroid
. - Nous faisons la plupart de notre travail dans la méthode
OnElementChanged
, où nous instancions et configurons notre contrôle natif.
Consommer le contrôle personnalisé
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CheckBoxCustomRendererExample" x:Class="CheckBoxCustomRendererExample.CheckBoxCustomRendererExamplePage">
<StackLayout Padding="20">
<local:Checkbox Color="Aqua" />
</StackLayout>
</ContentPage>
Création du moteur de rendu personnalisé sur chaque plate-forme
Le processus de création de la classe de rendu personnalisé est le suivant:
- Créez une sous-classe de la classe
ViewRenderer<T1,T2>
qui affiche le contrôle personnalisé. Le premier argument de type doit être le contrôle personnalisé utilisé par le moteur de rendu, dans ce cas,CheckBox
. Le deuxième argument de type doit être le contrôle natif qui implémentera le contrôle personnalisé. - Remplacez la méthode
OnElementChanged
quiOnElementChanged
le contrôle personnalisé et écrit la logique pour le personnaliser. Cette méthode est appelée lorsque le contrôleXamarin.Forms
correspondant est créé. - Ajoutez un attribut
ExportRenderer
à la classe de rendu personnalisée pour indiquer qu'elle sera utilisée pour effectuer le rendu du contrôle personnaliséXamarin.Forms
. Cet attribut est utilisé pour enregistrer le moteur de rendu personnalisé avecXamarin.Forms
.
Création du moteur de rendu personnalisé pour Android
[assembly: ExportRenderer(typeof(Checkbox), typeof(CheckBoxRenderer))]
namespace CheckBoxCustomRendererExample.Droid
{
public class CheckBoxRenderer : ViewRenderer<Checkbox, CheckBox>
{
private CheckBox checkBox;
protected override void OnElementChanged(ElementChangedEventArgs<Checkbox> e)
{
base.OnElementChanged(e);
var model = e.NewElement;
checkBox = new CheckBox(Context);
checkBox.Tag = this;
CheckboxPropertyChanged(model, null);
checkBox.SetOnClickListener(new ClickListener(model));
SetNativeControl(checkBox);
}
private void CheckboxPropertyChanged(Checkbox model, String propertyName)
{
if (propertyName == null || Checkbox.IsCheckedProperty.PropertyName == propertyName)
{
checkBox.Checked = model.IsChecked;
}
if (propertyName == null || Checkbox.ColorProperty.PropertyName == propertyName)
{
int[][] states = {
new int[] { Android.Resource.Attribute.StateEnabled}, // enabled
new int[] {Android.Resource.Attribute.StateEnabled}, // disabled
new int[] {Android.Resource.Attribute.StateChecked}, // unchecked
new int[] { Android.Resource.Attribute.StatePressed} // pressed
};
var checkBoxColor = (int)model.Color.ToAndroid();
int[] colors = {
checkBoxColor,
checkBoxColor,
checkBoxColor,
checkBoxColor
};
var myList = new Android.Content.Res.ColorStateList(states, colors);
checkBox.ButtonTintList = myList;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (checkBox != null)
{
base.OnElementPropertyChanged(sender, e);
CheckboxPropertyChanged((Checkbox)sender, e.PropertyName);
}
}
public class ClickListener : Java.Lang.Object, IOnClickListener
{
private Checkbox _myCheckbox;
public ClickListener(Checkbox myCheckbox)
{
this._myCheckbox = myCheckbox;
}
public void OnClick(global::Android.Views.View v)
{
_myCheckbox.IsChecked = !_myCheckbox.IsChecked;
}
}
}
}
Création du moteur de rendu personnalisé pour iOS
Comme dans iOS, la case à cocher n'est pas intégrée, nous allons d'abord créer un CheckBoxView
puis créer un moteur de rendu pour notre case à cocher Xamarin.Forms.
Le CheckBoxView
est basé sur deux images, checked_checkbox.png et unchecked_checkbox.png, afin que la propriété Color
soit ignorée.
La vue CheckBox:
namespace CheckBoxCustomRendererExample.iOS
{
[Register("CheckBoxView")]
public class CheckBoxView : UIButton
{
public CheckBoxView()
{
Initialize();
}
public CheckBoxView(CGRect bounds)
: base(bounds)
{
Initialize();
}
public string CheckedTitle
{
set
{
SetTitle(value, UIControlState.Selected);
}
}
public string UncheckedTitle
{
set
{
SetTitle(value, UIControlState.Normal);
}
}
public bool Checked
{
set { Selected = value; }
get { return Selected; }
}
void Initialize()
{
ApplyStyle();
TouchUpInside += (sender, args) => Selected = !Selected;
// set default color, because type is not UIButtonType.System
SetTitleColor(UIColor.DarkTextColor, UIControlState.Normal);
SetTitleColor(UIColor.DarkTextColor, UIControlState.Selected);
}
void ApplyStyle()
{
SetImage(UIImage.FromBundle("Images/checked_checkbox.png"), UIControlState.Selected);
SetImage(UIImage.FromBundle("Images/unchecked_checkbox.png"), UIControlState.Normal);
}
}
}
Le moteur de rendu personnalisé CheckBox:
[assembly: ExportRenderer(typeof(Checkbox), typeof(CheckBoxRenderer))]
namespace CheckBoxCustomRendererExample.iOS
{
public class CheckBoxRenderer : ViewRenderer<Checkbox, CheckBoxView>
{
/// <summary>
/// Handles the Element Changed event
/// </summary>
/// <param name="e">The e.</param>
protected override void OnElementChanged(ElementChangedEventArgs<Checkbox> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
BackgroundColor = Element.BackgroundColor.ToUIColor();
if (e.NewElement != null)
{
if (Control == null)
{
var checkBox = new CheckBoxView(Bounds);
checkBox.TouchUpInside += (s, args) => Element.IsChecked = Control.Checked;
SetNativeControl(checkBox);
}
Control.Checked = e.NewElement.IsChecked;
}
Control.Frame = Frame;
Control.Bounds = Bounds;
}
/// <summary>
/// Handles the <see cref="E:ElementPropertyChanged" /> event.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("Checked"))
{
Control.Checked = Element.IsChecked;
}
}
}
}
Résultat: