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
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).
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 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
Let's start with Android
Here we have our
renderer, which is properly exported and registered to be linked with our new control,
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
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.
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 a
Xamarin.Formsworld and transforms it into
Colorclass 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
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
Time to look at iOS
The same as before, our iOS
renderer is properly registered to be used with our
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
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
An speaking of extension methods, we just needed
ToCGColor method, which takes a Xamarin.Forms color and convert it to
CGColor needed by iOS.