Xamarin.Forms: Customizing our Entry control (Custom renderer)
- 4 min read
If you ever have worked with Xamarin.Forms, you definitively noticed that our entry control (most used control) looks pretty different between platforms (iOS and Android).
But, our designs most of the time should look the same to accomplish a look & feel like this:
So I took on the task of extending our Entry
control to enable customizations like BorderColor
, Padding
and CornerRadius
.
If you prefer you can watch this video about it (sad to admit that it’s in Spanish, by the way but an English version is coming so subscribe and keep tune in).
TLDR;
If you prefer to review our customization code and include it in your project, you can check the full source code available in Github https://github.com/jesulink2514/XamBooksApp/tree/feature/feat-entry
Let’s explore these customizations
To begin with, we used my XamBooksApp **** project available in Github in case you want to check the code.
I’ve created our [StandardEntry](https://github.com/jesulink2514/XamBooksApp/blob/feature/feat-entry/XamBooksApp/XamBooksApp/Controls/StandardEntry.cs)
class, this class extends Xamarin.Forms’ control and includes some additional properties.
As you can see, in this case, there is not much code in our class because almost everything of the personalization code resides in each platform project. As you can imagine in our Custom Renderers
.
Let’s start with Android
Here we have our renderer
, which is properly exported and registered to be linked with our new control, StandarEntry
.
Obviously, we don’t want to lose base functionality already implemented by Xamarin.Forms’ team, we just want to extend it so our renderer inherits from EntryRenderer
.
To make it works in Android, we need to define a constructor that receives an Android Context parameter.
Now it’s time to override CreateNativeControl
method, not for replacing our FormsEditText
with other native control, we’re going to keep it but I want to make sure that our Background
is updated when our native control is created taking into account our new properties.
For this, we’re going to use this method, UpdateBackground
, here is where all magic happens.
In our case, given that we’ve extended EntryRenderer
class, its property: Element
returns an instance of Entry
but it holds a StandardEntry
(you can review about basic renderer properties here). This property gives us access to Xamarin.Forms control instance, in other words, to our abstraction in our cross-platform project, my StandardEntry
. Sad to say we can’t override this property so we’ve defined a new property which does the casting
for us, our objective here is made easier to access our new properties.
You might notice that we’ve overridden OnElementPropertyChanged
method to allow us to react to properties changes inside our control. You must not forget to call base class implementation at the end.
So take a look at this Android code snippet which is used to apply required customizations.
Using a GradientDrawable
as background for our control gives us all that we need like background, border, etc. It’s worthy to mentioned these extension methods that Xamarin.Forms’ team put to our disposition to write code that interacts with platform specifics.
ToAndroid
, this extension method takes aColor
instance fromXamarin.Forms
world and transforms it intoColor
class that Android needs.ToPixels
, this extension method takes an independent pixel density measurement (a number) and converts it into the pixels equivalent.
Both methods extends Android Context
class.
Finally, we take our Padding
property in form of Xamarin.Forms Thicknes
instance and extract from it each of its components. The same as before, we must convert these values to pixels.
To complete this renderer, we must override a method called UpdateBackgroundColor
, which is already in use by base class when we update BackgroundColor
property.
Time to look at iOS
The same as before, our iOS renderer
is properly registered to be used with our StandardEntry
control.
We can spot our first difference, our renderer doesn’t extend EntryRenderer
, instead of it extend EntryRendererBase
. If we review Xamarin.Forms source code, given that it’s an open source project and there is no better way to learn about renderers than check it out, we would notice that Xamarin’s team have created a generic class to be easier to replace UITextField
native control with a class that extends it.
But, wait a minute, Why do we need a UITextField
derived class? That’s what I was wondering till I tried to make padding works in iOS.
To make padding works I need to override TextRect
, PlaceholderRect
and EditingRect
method, these methods are used to determine the sizing of showed text, placeholder and the editing rect. To accomplish this goal, we’re using a native iOS feature called UIEdgeInsets
(closets feature to our idea of padding).
Similar to Android implementation, we’ve created a ElementV2
property, in order to get access to new properties defined in our derived control.
In order to use our new UITextFieldPadding
class and update its background we’ve overriden CreateNativeControl
method, this time this makes all sense due to replacement of native control.
Probably you noticed similarity with Android, here in iOS background is defined used Layer
property.
An speaking of extension methods, we just needed ToCGColor
method, which takes a Xamarin.Forms color and convert it to CGColor
needed by iOS.
Y voilá …
https://github.com/jesulink2514/XamBooksApp/tree/feature/feat-entry