One of the most initially confusing, yet essential components to Xamarin.Forms are custom renderers. If you look at almost any advanced feature or customization tutorial for Forms, you are likely to run into the term custom renderer. But what the heck is a custom renderer?!? Everyone seems to reference the use of them, yet no one seems to take the time to thoroughly explain what they are and how they work.
Custom renderers are really simple once you understand the foundation behind how Forms renderers the user interface. Forms maps every UI element to each of the native platforms’ UI elements. In other words, Forms has generic views/controls that are referenced in XAML and are transformed into the native platforms equivalent view. For example, Forms has a Xamarin.Forms.Button class, which gets rendered to UIKit.UIButton on iOS, and android.widget.Button on Android. Essentially, a renderer is simply a mapping between a Forms element, and a platform’s native element. A custom renderer goes one step further; the developer, can override or extend Xamarin’s renderer.
Why would we ever want to change Xamarin’s default renderer? While Xamarin implements a majority of our UI/UX needs, we might need more granular control over the look or behavior of our views.
How do we create a custom renderer? A simple scenario (yet annoying) that requires the use of a custom renderer is when you want to prevent autocorrect on an Entry field when rendered on iOS. An Entry field is Forms’ version of a textbox. Unfortunately, by default on iOS, the textbox has autocorrection and first letter capitalization turned on, yet Forms does not provide a simple way to disable these settings. This is an example of a situation where a custom renderer is required to accomplish our goal.
Suppose you have a simple login page that uses an Entry field for the username and password:
Notice that we are using the default Entry tags in the LoginPage’s XAML. The magic does not happen within the portable class library (PCL); rather, all of our customization will be handled in each platforms’ native project.
- For this example, create a folder in the iOS project called: Renderers
- Within that new folder, create a new class called: CustomEntryRenderer
- Add the following line to the class before the namespace: [assembly: ExportRenderer(typeof(Entry), typeof(MyCoolApp.iOS.CustomEntryRenderer))]
- Have the class inherit from: EntryRenderer
- Override: OnElementChanged
Within a custom renderer class, there are two important properties to be aware of, Control and Element. The Control property refers to the platform’s native view. The Element is the Forms’ mapping to the Control. For this simple example, we only need to manipulate two settings on the native Control, AutocapitalizationType and AutocorrectionType.
Now, whenever we use an Entry element within our PCL project, this custom renderer will override the default iOS renderer due to the assembly reference we added before the namespace. One nice design aspect to note is that the our views are blissfully unaware of the custom renderer (i.e. they are loosely coupled). That also means that since we did not implement an Android custom renderer, Android will continue to use the default renderer.