I’m a big fan of Xamarin. It is, in my opinion, the best solution for cross-platform mobile development. Xamarin enables you to produce apps for iOS and Android, written in C#, and to share a large proportion of the code, with only the UI layers for each platform being written independently. The apps produced run natively on each platform, using proper native views.
I’d like to present a quick introduction to Xamarin.Forms. Xamarin.Forms takes another big step toward code-sharing. It allows you to share the UI code as well. So you can write code such as the following in a unified shared mobile project.
When compiled this will produce UITextField and UIButton UIViews on iOS, and EditText and Button Views on Android. Common properties and events are abstracted for us, so setting a property, such as Text, will actually set or call the appropriate native property or method on each platform.
When working with Forms, you may at some point need to do something more advanced than the standard controls will allow. Normally, when working with Xamarin, or indeed natively, you may create a custom view for each platform. With Xamarin Forms, under the hood, each type of control has a renderer, which handles the platform-specific code necessary to process and draw the control. To create custom functionality, or customise a view’s appearance, you can create a custom renderer.
The first step is to create a custom cross-platform view in your shared or PCL project. In this example, the custom view is just an empty class declaration.
The Entry control is a simple text box. Let’s customise this textbox on iOS and Android, by giving it some default text. To achieve this, create a custom renderer for both iOS and Android. These custom renderers will live in the platform specific project within the solution. Generally, when creating custom renderers, we still want all the usual functionality, so it’s normal to inherit from the default renderer for the control we’re customising. For the Entry control this is the EntryRenderer class.
You’ll notice the code above is nearly identical for both platforms. The renderer for each platform has access to the ‘native’ control, so you can utilise native APIs to add rich functionality where required.
Now we need to tell Xamarin that our custom control has a custom renderer, otherwise it will use the default EntryRenderer. To do this we simply add an attribute to each renderer. This is the same code for both platforms and must be specified before any namespaces.
The custom control can now be created in the shared project. This can be done in code as you’d expect, like this…
… or from your shared layout xml files. Note the extra namespace declaration.
Please note the following quote from the Xamarin developer documentation regarding namespaces in xaml when using Shared projects vs PCLs.
xmlnsis much simpler in PCLs than Shared Projects. A PCL is compiled into an assembly so it’s easy to determine what the
assembly=CustomRenderervalue should be. When using Shared Projects all the shared assets (including the Xaml) are compiled into each of the referencing projects, which means that if the iOS, Android and Windows Phone projects have their own assembly names it is impossible to to write the
xmlnsdeclaration because the value needs to be different for each application. Custom controls in Xaml for Shared Projects will require every application project to be configured with the same assembly name.
There we have it. A simple renderer for a text field for iOS and Android. This covers the basic technique for customising views on each platform. A key prinicple here is that you can access the platform-specific view from within a custom renderer by accessing the Control property, and casting it to the required type.
In a future post I’m going to expand on this technique, by solving a common Xamarin.Forms problem: how to add proper gesture support to shared controls.