Xamarin.Forms
Создание настраиваемых элементов управления
Поиск…
Вступление
В каждом представлении Xamarin.Forms
имеется сопроводительный рендерер для каждой платформы, который создает экземпляр встроенного элемента управления. Когда представление отображается на конкретной платформе, ViewRenderer
экземпляр класса ViewRenderer
.
Процесс для этого заключается в следующем:
Создайте пользовательский элемент управления Xamarin.Forms.
Потребляйте пользовательский контроль из Xamarin.Forms.
Создайте собственный рендер для элемента управления на каждой платформе.
Внедрение CheckBox Control
В этом примере мы реализуем пользовательский флажок для Android и iOS.
Создание пользовательского элемента управления
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);
}
}
}
Мы начнем с Android Custom Renderer, создав новый класс ( CheckboxCustomRenderer
) в части Android
нашего решения.
Несколько важных деталей:
- Нам нужно отметить верхнюю часть нашего класса атрибутом ExportRenderer, чтобы рендеринг был зарегистрирован с помощью
Xamarin.Forms
. Таким образом,Xamarin.Forms
будет использовать этот рендерер, когда он попытается создать наш объектCheckbox
наAndroid
. - Мы выполняем большую часть нашей работы в методе
OnElementChanged
, где мы создаем и настраиваем наш собственный элемент управления.
Потребление пользовательского контроля
<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>
Создание пользовательского рендерера на каждой платформе
Процесс создания пользовательского класса визуализатора выглядит следующим образом:
- Создайте подкласс класса
ViewRenderer<T1,T2>
который отображает настраиваемый элемент управления. Аргументом первого типа должен быть пользовательский элемент управления, на который выполняется средство визуализации, в данном случаеCheckBox
. Аргументом второго типа должен быть собственный элемент управления, который будет реализовывать пользовательский элемент управления. - Переопределите метод
OnElementChanged
который отображает пользовательский контроль и логику записи для его настройки. Этот метод вызывается, когдаXamarin.Forms
соответствующее управлениеXamarin.Forms
. - Добавьте атрибут
ExportRenderer
в собственный класс визуализатора, чтобы указать, что он будет использоваться для визуализации настраиваемогоXamarin.Forms
управленияXamarin.Forms
. Этот атрибут используется для регистрации пользовательского рендеринга с помощьюXamarin.Forms
.
Создание пользовательского рендеринга для 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;
}
}
}
}
Создание пользовательского рендерера для iOS
Поскольку в iOS флажок не установлен, мы сначала создадим CheckBoxView
а затем создадим рендер для нашего флажка Xamarin.Forms.
CheckBoxView
основан на двух изображениях checked_checkbox.png и unchecked_checkbox.png, поэтому свойство Color
будет проигнорировано.
Вид 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);
}
}
}
Пользовательский рендеринг 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;
}
}
}
}
Результат: