Xamarin.Forms – Renderers

User interface in Xamarin.Forms is rendered using native controls of the target platform. We can affect this process using custom renderers which allow to customize appearance.

In my project I wanted to achieve the same appearance for buttons on each platform. Now they look like this:

On iOS:

On Android:

with the following code:

<Button Text="LOG IN" Command="{Binding LoginCommand}" Style="{StaticResource buttonStyle}" Grid.Row="1"/>

and custom style:

<Style x:Key="buttonStyle" TargetType="Button">
   <Setter Property="HorizontalOptions" Value="Center" /
   <Setter Property="VerticalOptions" Value="CenterAndExpand" />
   <Setter Property="WidthRequest" Value="200" />
   <Setter Property="BorderWidth" Value="5" />
   <Setter Property="TextColor" Value="#FFBF65" />
</Style>

But this is not enough to meet requirements of anyone. So I had to write a custom renderers for button. I will show you how to create your own custom renderer through my example.

First in platform project create a subclass of a renderer class that renders the native control.
The list of renderer base classes you can findĀ here.

Add an ExportRenderer attribute above namespace in your custom renderer class.

[assembly: ExportRenderer(typeof(Button), typeof(<Your-custom-renderer-class))]

and override the method that renders native control (OnElementChanged) and write your code.
From renderer you have a full access to native control.

Renderer for Android platform:

[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(TransparentButtonRenderer))]
namespace NotifyMe.App.Droid.Renderers
{
    public class TransparentButtonRenderer : ButtonRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);

            if(Control != null)
            {
	        var borderWidth = 5;
	        var cornerRadius = 40;

                var gradient = new GradientDrawable();
                gradient.SetColor(Android.Graphics.Color.Transparent);
                gradient.SetStroke(borderWidth, Colors.Primary.ToAndroid());
                gradient.SetCornerRadius(cornerRadius);

                var states = new StateListDrawable();
                states.AddState(new int[] { }, gradient);
                Control.SetBackground(states);

                Control.Touch += (sender, args) =>
                {
                    if (args.Event.Action == MotionEventActions.Down)
                    {
                        Control.SetTextColor(Colors.SecondPrimary.ToAndroid());
                        gradient.SetStroke(borderWidth, Colors.SecondPrimary.ToAndroid());
                    }
                    else if (args.Event.Action == MotionEventActions.Up)
                    {
                        Control.SetTextColor(Colors.Primary.ToAndroid());
                        gradient.SetStroke(borderWidth, Colors.Primary.ToAndroid());
                    }

                    args.Handled = false;
                };
            }
        }
    }
}

and renderer for iOS platform:

[assembly: ExportRenderer(typeof(Button), typeof(TransparentButtonRenderer))]
namespace NotifyMe.App.iOS
{
	public class TransparentButtonRenderer : ButtonRenderer
	{
		UIButton button;

		public override void Draw(CoreGraphics.CGRect rect)
		{
			base.Draw(rect);

			button.Layer.MasksToBounds = true;
			button.Layer.BorderColor = Colors.Primary.ToCGColor();
			button.Layer.CornerRadius = 20;
			button.Layer.BorderWidth = 3;
			button.SetTitleColor(Colors.Primary.ToUIColor(), UIControlState.Normal);
			button.TintColor = Colors.Background.ToUIColor();

			button.TouchDown += (sender, e) =>
			{
				button.Layer.BorderColor = Colors.SecondPrimary.ToCGColor();
			};

			button.TouchUpInside += (sender, e) =>
			{
				button.Layer.BorderColor = Colors.Primary.ToCGColor();
			};
		}

		protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
		{
			base.OnElementChanged(e);

			if (Control != null)
			{
				button = (UIButton)Control;
			}
		}
	}
}

Finally, results of these renderers:

On iOS:

On Android:

Custom renderers are a really powerful tool. You can write renderers for your custom Xamarin.Forms controls, layouts, views, cells or even pages. Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *