While Xamarin.Forms provides a unified way to also create our UI from a single code base, the default controls tend to be just that; default controls.
Don’t get me wrong, I am very happy with these controls and they can be used to create simple, no-fancy-design-needed apps. But when you have created some apps, you want a little bit more. You have to stand out between all the other apps already out there and how to do that better then with an awesome UI?
Luckily for us, Xamarin already foresaw this and gave us something that is called Custom Renderers. With custom renderers we’re able to render controls in our own way, rather than having Xamarin rendering it to the default control for that platform. With this we can customise how an image looks for example. And this is exactly what we will be doing, turn our UI into something magical like we are the fairy godmother herself!
Right now my 4DotNet app has the default implementation of a ListView with Image Cells. This shows up in the app like this:

It looks ok! But why settle for ok if we can have AWESOME?
For mobile apps, especially for profile pictures, it seems to be required that they are shown as circular images rather than the squares I have now. Let’s see if we can turn this around.
Now let us work some magic.
To work with our custom renderer, we first have to create our own image type. Let’s call this CircularImage.
This type we can use in all our apps, so put it in the shared project of your solution.
1
2
3
4
5
6
|
namespaceFourDotNet.Controls
{
publicclassCircularImage:Image
{
}
}
|
Our CircularImage inherits from the default Xamarin.Forms.Image. If you like you could add some custom properties and other stuff in there, but for what we’ll be doing right now that won’t be necessary.
Now the rest consists of creating a custom renderer per platform. These I will name the CircularImageRenderer and these will inherit from the default Xamarin.Forms ImageRenderer, which will be the platform specific one (i.e. Xamarin.Forms.Platforms.iOS.ImageRenderer).
1
2
3
4
|
publicclassCircularImageRenderer:ImageRenderer
{
// TODO
}
|
Bibbidi-Bobbidi-iOS!
Let’s start with iOS.
We create our new file according to the above empty class and declare our iOS CircularImageRenderer.
1
2
3
4
5
6
7
8
9
|
privatevoidDrawCircle()
{
doublemin=Math.Min(Element.Width,Element.Height);
Control.Layer.CornerRadius=(float)(min/2.0);
Control.Layer.MasksToBounds=false;
Control.Layer.BorderColor=Color.White.ToCGColor();
Control.Layer.BorderWidth=3;
Control.ClipsToBounds=true;
}
|
We start with defining a custom private method which transforms our square image to a round one and adds a border around it so it looks extra fancy.
In itself this does nothing, because we have to override our default renderer behaviour to make this transformation visible. So we override the OnElementChanged and OnElementPropertyChanged method like underneath.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
protectedoverride voidOnElementChanged(ElementChangedEventArgs<Image>e)
{
base.OnElementChanged(e);
if(e.OldElement!=null||Element==null)
return;
DrawCircle();
}
protectedoverride voidOnElementPropertyChanged(objectsender,PropertyChangedEventArgse)
{
base.OnElementPropertyChanged(sender,e);
if(e.PropertyName==VisualElement.HeightProperty.PropertyName||e.PropertyName==VisualElement.WidthProperty.PropertyName)
{
DrawCircle();
}
}
|
With this code we respond to the event which is fired when the Element (Image in this case) has changed or any property of the Element has changed.
Within the ElementChanged we just check for nulls and then draw our CircularImage, with the PropertyChanged we check if the changed property has anything to do with the appearance of our Image. If so, we then redraw, if not, we do nothing.
That concludes the code we have to write for our renderer, that wasn’t so bad now, was it?
There is one vital line we have to add. We have to tell Xamarin that whenever it finds our custom control CircularImage, that there is a custom renderer for that. We do that in the same way as we saw in my previous post about Dependency Injection.
1
2
3
4
5
6
7
8
|
[assembly:ExportRenderer(typeof(CircularImage),typeof(CircularImageRenderer))]
namespaceFourDotNet.iOS.CustomRenderers
{
publicclassCircularImageRenderer:ImageRenderer
{
// … The above code is here
}
}
|
Note the first line here. We state that we export a renderer for our type CircularImage, and that renderer is of our type CircularImageRenderer.
Bibbidi-Bobbidi-Android!
On to our Android renderer.
As you might expect this process will be roughly the same, only the implementation will be different. However, this is more true for Windows Phone than Android. On Android there is no physical layer to interact with, so instead we need to override the method that Xamarin uses to draw the child controls.
We can do this by using the below code;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
protectedoverride boolDrawChild(Canvas canvas,View child,longdrawingTime)
{
varradius=Math.Min(Width,Height)/2;
varstrokeWidth=10;
radius-=strokeWidth/2;
//Create path to clip
varpath=newPath();
path.AddCircle(Width/2,Height/2,radius,Path.Direction.Ccw);
canvas.Save();
canvas.ClipPath(path);
varresult=base.DrawChild(canvas,child,drawingTime);
canvas.Restore();
// Create path for circle border
path=newPath();
path.AddCircle(Width/2,Height/2,radius,Path.Direction.Ccw);
varpaint=newPaint();
paint.AntiAlias=true;
paint.StrokeWidth=5;
paint.SetStyle(Paint.Style.Stroke);
paint.Color=Color.White;
canvas.DrawPath(path,paint);
//Properly dispose
paint.Dispose();
path.Dispose();
returnresult;
}
|
Also, since API Level 18, hardware acceleration for drawing was introduced. As you might know, that is something you’d want to use!
You can set a flag to use software rendering for below API Level 18 in the OnElementChanged event like below.
1
2
3
4
5
6
7
8
9
10
|
protectedoverride voidOnElementChanged(ElementChangedEventArgse)
{
base.OnElementChanged(e);
if(e.OldElement==null)
{
if((int)Android.OS.Build.VERSION.SdkInt<18)
SetLayerType(LayerType.Software,null);
}
}
|
Of course, don’t forget to export your renderer!
Bibbidi-Bobbidi-Windows Phone!
The Windows Phone renderer is again a bit easier. We can just use the Clip property here and assign a EllipseGeometry to it, like so.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
protectedoverride voidOnElementPropertyChanged(objectsender,System.ComponentModel.PropertyChangedEventArgse)
{
base.OnElementPropertyChanged(sender,e);
if(Control!=null&&Control.Clip==null)
{
varmin=Math.Min(Element.Width,Element.Height)/2.0f;
if(min<=0)
return;
Control.Clip=newEllipseGeometry
{
Center=newSystem.Windows.Point(min,min),
RadiusX=min,
RadiusY=min
};
}
}
|
And again, let’s not forget to register our custom renderer.
1
2
3
4
5
|
[assembly:ExportRenderer(typeof(ImageCircle),typeof(ImageCircleRenderer))]
namespaceFourDotNet.iOS.CustomRenderers
{
// …
}
|
For the last bit we have to use our new CircularImage and see how all this looks like.
Before I have used a ListView with an ImageCell, in XAML that looks like this.
1
2
3
4
5
6
7
8
9
10
11
|
<ListView IsPullToRefreshEnabled=“True”Refreshing=“EmployeeListView_OnRefreshing”ItemTapped=“EmployeeListView_OnItemTapped”x:Name=“EmployeeListView”>
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource=“{Binding PhotoUrl}”Text=“{Binding Name}”Detail=“{Binding Function}”>
<ImageCell.ContextActions>
<MenuItem Text=“Stuur e-mail”Clicked=“EmployeeContextEmail_OnClicked”></MenuItem>
</ImageCell.ContextActions>
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
|
Of course an ImageCell is a composite of a few controls already which acts as a template for a list item. although you can create your own custom cell, for now I will create my own list item template right here in the ListView. This probably isn’t what you would want in your final application, but for the sake of this example it will do.
In the underneath code you will see how I replaced the ImageCell with my own template and made it look similar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<ContentPage xmlns=“http://xamarin.com/schemas/2014/forms”
xmlns:x=“http://schemas.microsoft.com/winfx/2009/xaml”
xmlns:controls=“clr-namespace:FourDotNet.Controls;assembly=FourDotNet”
x:Class=“FourDotNet.Pages.EmployeesPage”
Title=“Medewerkers”>
<!—...Some XAML omitted here...—>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text=“Stuur e-mail”Clicked=“EmployeeContextEmail_OnClicked”/>
</ViewCell.ContextActions>
<StackLayout Orientation=“Horizontal”>
<controls:CircularImage Source=“{Binding PhotoUrl}”/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=“*”/>
<RowDefinition Height=“*”/>
</Grid.RowDefinitions>
<Label YAlign=“End”Grid.Row=“0”Text=“{Binding Name}”TranslationY=“4”/>
<Label YAlign=“Start”Grid.Row=“1”Text=“{Binding Function}”FontSize=“Micro”TextColor=“Accent”/>
</Grid>
</StackLayout>
</ViewCell>
</ListView.ItemTemplate>
</ListView>
<!—...Some XAML omitted here...—>
</ContentPage>
|
You will notice that you have to specify a new namespace which specifies where my custom CircularImage resides. In this case I have used ‘controls’.
Now with this new namespace I can define my CircularImage control just like any other ‘normal’ control.
When we run this on all of the different platforms, you will see an enchanting result…!

To create these custom renderers I have followed another blog-post by James Montemagno and the documentation of Xamarin, so code similarities might be apparent. All credits for the math-hocus-pocus goes to him/them.