Что такое Custom Renderer и зачем он нужен?

В Xamarin.Forms Custom Renderer (пользовательский рендерер) — это механизм, позволяющий разрабатывать платформенно-специфические реализации визуальных компонентов и логики для элементов управления Xamarin.Forms. Он используется в тех случаях, когда стандартного поведения элемента недостаточно, и требуется доступ к нативным API Android, iOS или UWP, чтобы изменить внешний вид или функциональность контрола.

Custom Renderers расширяют или полностью заменяют стандартную отрисовку компонентов Xamarin.Forms на конкретной платформе. Они обеспечивают мощный способ внедрения низкоуровневого контроля при сохранении общего кода приложения в .NET Standard.

Когда нужен Custom Renderer

Custom Renderer необходим, когда:

  1. Нужно изменить визуальное поведение стандартного элемента (например, Entry, Button, Label, Image).

  2. Требуется интеграция с нативными возможностями платформы (например, UIView, Android.Widget).

  3. Необходимо добавить свойства, отсутствующие в Xamarin.Forms.

  4. Хочется полностью заменить визуальный элемент на нативный (например, использовать MDCButton на Android вместо стандартного Button).

  5. Требуется использовать сторонние нативные компоненты SDK.

Архитектура рендереров

Xamarin.Forms работает по принципу абстракции UI, где один и тот же элемент (Label, Button, Entry) отображается по-разному на каждой платформе через соответствующий рендерер.

Xamarin.Forms элемент iOS Android UWP
Label UILabel TextView TextBlock
--- --- --- ---
Button UIButton Button Button
--- --- --- ---
Entry UITextField EditText TextBox
--- --- --- ---

Custom Renderer позволяет перехватить этот процесс и изменить его.

Как создать Custom Renderer

Шаг 1. Создать кастомный элемент в .NET Standard проекте

public class MyEntry : Entry
{
// можно добавить дополнительные свойства
}

Шаг 2. Создать рендерер в проекте платформы

Пример: Android

\[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))\]
namespace MyApp.Droid.Renderers
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.SetBackgroundColor(Android.Graphics.Color.LightGreen);
Control.SetPadding(20, 20, 20, 20);
}
}
}
}

Пример: iOS

\[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))\]
namespace MyApp.iOS.Renderers
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BackgroundColor = UIColor.LightGray;
Control.Layer.CornerRadius = 10;
}
}
}
}

Ключевые методы и свойства

  • OnElementChanged() — вызывается при присоединении элемента, здесь можно менять нативный контрол (Control).

  • OnElementPropertyChanged() — вызывается при изменении свойства элемента Xamarin.Forms.

  • Dispose() — освобождение ресурсов.

  • Element — элемент Xamarin.Forms.

  • Control — нативный визуальный элемент (например, UIButton, EditText).

  • Container — контейнер элемента (иногда FrameLayout, UIView и т. п.).

Добавление платформенных свойств

Custom Renderers могут внедрять свойства, недоступные в общем API Xamarin.Forms.

Пример: добавить ввод только цифр в Entry на Android:

Control.InputType = Android.Text.InputTypes.ClassNumber;

Или тень у кнопки на iOS:

Control.Layer.ShadowColor = UIColor.Black.CGColor;
Control.Layer.ShadowOpacity = 0.5f;
Control.Layer.ShadowOffset = new CGSize(2, 2);
Control.Layer.MasksToBounds = false;

Часто используемые рендереры

Контрол Изменения
Button Цвета, границы, анимации, 3D
--- ---
Entry Отключение подчеркивания, изменение шрифта
--- ---
Image Углы, нативные фреймворки (FFImageLoading)
--- ---
ListView Кастомные деления, цвет строк
--- ---
Map Поддержка карт Google или Apple, кастомные пины
--- ---

Сравнение с другими расширениями

Подход Назначение Поддержка MVVM Кроссплатформенность Платформенный код
Effect Визуальные мелкие изменения Да Частично Да (в каждой платформе)
--- --- --- --- ---
Behavior Поведение UI, без визуальных эффектов Да Да Нет
--- --- --- --- ---
Custom Renderer Глубокие визуальные изменения или нативный UI Нет Нет (для каждой платформы отдельно) Да
--- --- --- --- ---

Комбинирование с DependencyService

Иногда Custom Renderer работает в связке с DependencyService, чтобы вызвать нативную функцию и визуально отобразить её результат (например, сканирование QR-кода или биометрия).

Практические примеры

Пример 1: Убрать подчёркивание у Entry на Android

Control.Background = null;

Пример 2: Настроить высоту кнопки

iOS

Control.Frame = new CoreGraphics.CGRect(Control.Frame.X, Control.Frame.Y, Control.Frame.Width, 60);

Android

Control.SetHeight(200);

Подводные камни и ограничения

  1. Платформенная зависимость — необходимо поддерживать код для каждой платформы отдельно.

  2. Обновления API — при выходе новых версий Android/iOS может потребоваться обновление рендереров.

  3. Производительность — избыточное использование рендереров может замедлить рендеринг страницы.

  4. Тестирование — требует запуска на реальных устройствах или эмуляторах платформы.

Советы по разработке

  • Используйте ExportRenderer с правильными using и атрибутами.

  • Минимизируйте платформенный код в рендерерах — выносите логику в сервисы при необходимости.

  • Проверяйте Control != null перед изменением свойств.

  • Обрабатывайте OnElementPropertyChanged для реагирования на изменение BindableProperty.

  • Вызывайте SetNativeControl() в кастомных рендерерах только один раз — при инициализации.

Custom Renderer предоставляет полный контроль над отображением и поведением элементов управления на уровне нативной платформы. Этот механизм позволяет Xamarin.Forms приложениям выглядеть и вести себя максимально естественно и "по-платформенному", при этом сохраняя общую кодовую базу. Это важный инструмент для разработчиков, стремящихся к глубокому кастомизированному UI или специфичным нативным функциям.