Who knew it could be so difficult to just put a number on a circle in Xamarin.Forms? Here’s a freebie to make your life easier in creating your own badges.
Before we dive in, I want to note that with the Xamarin.Forms.Themes, this can be easier. Check out the docs here: https://developer.xamarin.com/guides/xamarin-forms/user-interface/themes/. Basically, they added a StyleClass
for BoxView
that allows you to render it as a circle (although I’ve had problems with it in the past). This example is going to be avoiding the Themes package with a custom rolled implementation.
To start, we are going to create a custom CircleView
. That CircleView
is going to inherit from BoxView
and use a custom renderer to give us the rounded edges we want. After that, we are going to make a reusable view called BadgeView
that will essentially just slap a Label
on top of our new CircleView
.
Start here, with your CircleView
in your PCL or Shared Library:
CircleView.cs
public partial class CircleView : BoxView { public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create(nameof(CornerRadius), typeof(double), typeof(CircleView), 0.0); public double CornerRadius { get { return (double)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); } } public CircleView() { InitializeComponent(); } }
Now let’s create our custom renderers. I want to note, that for iOS it is much simpler, and could also be done as an Effect
rather than a BoxRenderer
, however, in order to be consistent with the more complicated Android implementation, we are doing both as renderers.
First, and easiest – iOS:
CircleViewRenderer.cs
[assembly: ExportRenderer(typeof(CircleView), typeof(CircleViewRenderer))] namespace YourNamespace.iOS { public class CircleViewRenderer : BoxRenderer { protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e) { base.OnElementChanged(e); if (Element == null) return; Layer.MasksToBounds = true; Layer.CornerRadius = (float)((CircleView)Element).CornerRadius / 2.0f; } } }
and of course Android:
CircleViewRenderer.cs
[assembly: ExportRenderer(typeof(CircleView), typeof(CircleViewRenderer))] namespace YouNamespace.Droid { public class CircleViewRenderer : BoxRenderer { private float _cornerRadius; private RectF _bounds; private Path _path; protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e) { base.OnElementChanged(e); if (Element == null) { return; } var element = (CircleView)Element; _cornerRadius = TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)element.CornerRadius, Context.Resources.DisplayMetrics); } protected override void OnSizeChanged(int w, int h, int oldw, int oldh) { base.OnSizeChanged(w, h, oldw, oldh); if (w != oldw && h != oldh) { _bounds = new RectF(0, 0, w, h); } _path = new Path(); _path.Reset(); _path.AddRoundRect(_bounds, _cornerRadius, _cornerRadius, Path.Direction.Cw); _path.Close(); } public override void Draw(Canvas canvas) { canvas.Save(); canvas.ClipPath(_path); base.Draw(canvas); canvas.Restore(); } } }
Cool. Now we can draw pretty circles in our Xamarin.Forms views:
<views:CircleView CornerRadius="16" WidthRequest="16" HeightRequest="16"/>
Now let’s apply that to a reusable BadgeView
.
BadgeView.xaml
<Grid xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-namespace:your_local_namespace" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="your_local_namespace.BadgeView" HeightRequest="16" WidthRequest="16"> <local:CircleView x:Name="BadgeCircle" HeightRequest="16" WidthRequest="16" CornerRadius="16" VerticalOptions="Center" HorizontalOptions="Center" /> <Label x:Name="BadgeLabel" TextColor="White" VerticalOptions="Center" HorizontalOptions="Center" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" FontSize="10"/> </Grid>
BadgeView.xaml.cs
public partial class BadgeView : Grid { public static BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(BadgeView), "0", propertyChanged: (bindable, oldVal, newVal) => { var view = (BadgeView)bindable; view.BadgeLabel.Text = (string)newVal; }); public static BindableProperty BadgeColorProperty = BindableProperty.Create("BadgeColor", typeof(Color), typeof(BadgeView), Color.Blue, propertyChanged: (bindable, oldVal, newVal) => { var view = (BadgeView)bindable; view.BadgeCircle.BackgroundColor = (Color)newVal; }); public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public Color BadgeColor { get { return (Color)GetValue(BadgeColorProperty); } set { SetValue(BadgeColorProperty, value); } } public BadgeView() { InitializeComponent(); BadgeLabel.Text = Text; BadgeCircle.BackgroundColor = BadgeColor; } }
This is obviously a super simple example, but you can always add any other properties you want such as handling changing sizes, corners, shapes, colors, etc.
But now we can see our final results when using our control:
<Grid> <Label HorizontalTextAlignment="Center" Text="Look at me!"/> <views:BadgeView Text="3" BadgeColor="Green" VerticalOptions="Start" HorizontalOptions="End"/> </Grid>
If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!
How can I create custom renderers for UWP?
LikeLike
Good question! I’ll have to update this post later with the UWP implementation. I’ll also add a Github link to make it easier to pull and use.
LikeLike
Very good post!
LikeLike
Thank you 🙂
LikeLike
How can I create a partial class CircleView.cs with othe xaml file?
LikeLike
How can I create a partial class CircleView.cs without xaml file?
LikeLike
Hi, thanks for the example. can you post a link to the source code?
LikeLike
All the source code is here in the blog post. I haven’t added the full component to my GitHub yet, but when I do, you’ll be able to find it here: https://github.com/SuavePirate/BadgeView
LikeLike
Excelent post…thanks!!!
LikeLike
There is no source code in your git hub please provide a link to solution i am stuck at some steps
LikeLike
What are you stuck on? All the required source is in this post.
LikeLike
this line sir where should i add this in what part of solution
and i am stuck after this line
LikeLike
Your code didn’t come through
LikeLike
where i write this line
LikeLike
Your code won’t appear properly in the comments to avoid XSS. Try putting it in gist or sending me a link to your code.
LikeLike
<views:CircleView CornerRedius=16………
where i am write this line
LikeLike
That is part of the BadgeView.xaml. If you look above each block of code in the post, it tells you which file it belongs to in bold.
LikeLike
Thanks You Saved me 🙂
LikeLike
Sir Still I am Not able to complete my task please if possible upload the solution for referring
LikeLike
Here… I put the source as its own library with an example project. https://github.com/SuavePirate/BadgeView
LikeLike
Thankyou so much sir
LikeLike
This is a great article, thanks!
Any status update on UWP support?
LikeLike
It’s on my list of things but not an immediate priority. If you want to take a stab at it, I’m always accepting contributions to the repo.
LikeLike
Nice Alex! Love it and I’m going to use this sample on my project!
LikeLike
Hello Alex,
its not working in master detail page. can you tell me how I use inside master detail page?
LikeLike
Your master detail page has to contain content pages and this control goes inside those pages
LikeLike
Hi Alex,
i receive this error when i try to create a BadgeView
Xamarin.Forms.Xaml.XamlParseException: Position 8:81. Multiple properties with name ‘BadgeView.Shared.CircleView.CornerRadius’ found.
LikeLike
The latest version of xamarin forms has a corner radius property now so you don’t need to add one. When this post was written, there was no corner radius property.
LikeLike
Could you post the class where UWP implementation is implemented?
LikeLike
I never implemented it on UWP, however in the most recent version of Xamarin.Forms, you don’t need the CircleView anymore. You can use a BoxView with a CornerRadius property
LikeLike
Hi,
Good an clear example, thanks.. one thought though, do you think it would be possible to extend ToolbarItem (only for Android) similarly so that I can have these badges on the toolbar images? Would it be much more complicated? I have only done XF for 6 months, what you showed above was clear and understandable but have no deep experience in Renderers and the inner workings of the native platforms…
LikeLike
thank you for this. But can you tell me how we use inside toolbaritems? (xamarin forms)
LikeLike
https://www.xamboy.com/2018/03/08/adding-badge-to-toolbaritem-in-xamarin-forms/
LikeLike
Thank you for this, good job… Can you tell me how we use into ToolbarItems?
LikeLike
https://www.xamboy.com/2018/03/08/adding-badge-to-toolbaritem-in-xamarin-forms/
LikeLike