BadgeView – Xamarin.Forms

Olá, neste post irei demonstrar como criar um BadgeView utilizando custom renderer em aplicações Xamarin.Forms.

Em seu projeto portable, crie a classe CircleBox.


using Xamarin.Forms;
namespace BadgeView
{
public class CircleBox : BoxView
{
// Corner radius property.
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create("CornerRadius", typeof(double), typeof(CircleBox), 0.0);
// Get and set the corner radius.
public double CornerRadius
{
get { return (double) GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
}
}

view raw

CircleBox.cs

hosted with ❤ by GitHub

 

Ainda no portable, crie uma classe Badge, como demonstrado a seguir:


using System;
using Xamarin.Forms;
namespace BadgeView
{
public class Badge: AbsoluteLayout
{
protected Label Label;
protected CircleBox Box;
// Text property
public static readonly BindableProperty TextProperty =
BindableProperty.Create("Text", typeof(String), typeof(Badge), "");
//Box color property
public static readonly BindableProperty BoxColorProperty =
BindableProperty.Create("BoxColor", typeof(Color), typeof(Badge), Color.Default);
public Badge(double size, double fontSize)
{
HeightRequest = size;
WidthRequest = size;
// Box
Box = new CircleBox
{
CornerRadius = HeightRequest/2
};
Box.SetBinding(BackgroundColorProperty, new Binding("BoxColor", source: this));
Children.Add(Box, new Rectangle(0, 0, 1.0, 1.0), AbsoluteLayoutFlags.All);
// Label
Label = new Label
{
TextColor = Color.White,
FontSize = fontSize,
XAlign = TextAlignment.Center,
YAlign = TextAlignment.Center
};
Label.SetBinding(Label.TextProperty, new Binding("Text",BindingMode.OneWay, source: this));
Children.Add(Label, new Rectangle(0, 0, 1.0, 1.0), AbsoluteLayoutFlags.All);
// Auto width
SetBinding(WidthRequestProperty, new Binding("Text", BindingMode.OneWay, new BadgeWidthConverter(WidthRequest), source: this));
// If not value = hide
SetBinding(IsVisibleProperty, new Binding("Text", BindingMode.OneWay, new BadgeVisibleValueConverter(), source: this));
// Default color
BoxColor = Color.Red;
}
// Text
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Color of the box
public Color BoxColor
{
get { return (Color)GetValue(BoxColorProperty); }
set { SetValue(BoxColorProperty, value); }
}
}
class BadgeWidthConverter : IValueConverter
{
// Width ratio.
const double widthRatio = 0.33;
//Width of the base.
readonly double baseWidth;
public BadgeWidthConverter(double baseWidth)
{
this.baseWidth = baseWidth;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var text = value as string;
if ((text != null) && (text.Length > 1))
{
return baseWidth * (1 + widthRatio * (text.Length – 1));
}
return baseWidth;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
class BadgeVisibleValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var text = value as string;
return !String.IsNullOrEmpty(text);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

view raw

Badge.cs

hosted with ❤ by GitHub

 

(Portable):

badgeview-portable

Android

Em seu projeto .android crie a classe CircleBoxRenderer.


using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using System.ComponentModel;
using Android.Graphics;
using BadgeView;
using BadgeView.Droid;
[assembly: ExportRenderer(typeof(CircleBox), typeof(CircleBoxRenderer))]
namespace BadgeView.Droid
{
public class CircleBoxRenderer : BoxRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
{
base.OnElementChanged(e);
SetWillNotDraw(false);
Invalidate();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == CircleBox.CornerRadiusProperty.PropertyName)
{
Invalidate();
}
}
public override void Draw(Canvas canvas)
{
var box = Element as CircleBox;
var rect = new Rect();
var paint = new Paint()
{
Color = box.BackgroundColor.ToAndroid(),
AntiAlias = true,
};
GetDrawingRect(rect);
var radius = (float) (rect.Width() / box.Width * box.CornerRadius);
canvas.DrawRoundRect(new RectF(rect), radius, radius, paint);
}
}
}

 

.Android:

badgeview-android

iOS

Também crie uma classe CircleBoxRenderer no seu projeto .iOS, porém como demonstrada a seguir:


using Xamarin.Forms;
using BadgeView.iOS;
using BadgeView;
using Xamarin.Forms.Platform.iOS;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(CircleBox), typeof(CircleBoxRenderer))]
namespace BadgeView.iOS
{
public class CircleBoxRenderer : BoxRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
{
base.OnElementChanged(e);
if (Element != null)
{
Layer.MasksToBounds = true;
UpdateCornerRadius(Element as CircleBox);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == CircleBox.CornerRadiusProperty.PropertyName)
{
UpdateCornerRadius(Element as CircleBox);
}
}
void UpdateCornerRadius(CircleBox box)
{
Layer.CornerRadius = (float)box.CornerRadius;
}
}
}

 

.iOS:

badgeview solution

 

 

Pronto, seu BadgeView já esta criado e agora você pode utiliza-lo em qualquer página do seu aplicativo.

 

Xaml

No arquivo xaml, crie um “Badge”, adicione a cor desejada na propriedade “BoxColor”, informe o tamanho do círculo nas propriedades “WidthRequest” e “HeightRequest”. Por último, passe dois argumentos do tipo Double, sendo eles: CornerRadius e FontSize (Tamanho do texto no interior do Badge).

Apenas para fins de demonstração eu adicionei um botão que quando clicado irá incrementar o valor 1 no contador de notificações.  Porém, no seu caso você pode realizar binding com a propriedade que desejar. (<local:Badge Text=”{Binding Notifications}”)


<ContentPage.Content>
<StackLayout VerticalOptions="Center">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center">
<Label HorizontalTextAlignment="Center" Text="Notifications" FontSize="18"/>
<local:Badge x:Name="BadgeNotifications" BoxColor="red"
WidthRequest="18" HeightRequest="18"
VerticalOptions="Center" HorizontalOptions="Center">
<x:Arguments>
<x:Double>30</x:Double>
<x:Double>10</x:Double>
</x:Arguments>
</local:Badge>
</StackLayout>
<Button Text="Add Notification" Clicked="AddNotification"/>
</StackLayout>
</ContentPage.Content>

C#


public MainPage()
{
InitializeComponent();
BadgeNotifications.Text = "2";
}
private void AddNotification(object sender, EventArgs e)
{
if (BadgeNotifications.Text != "99+" && int.Parse(BadgeNotifications.Text) < 99 )
BadgeNotifications.Text = (int.Parse(BadgeNotifications.Text)+1).ToString();
else
{
BadgeNotifications.Text = "99+";
}
}

view raw

BadViewPage.cs

hosted with ❤ by GitHub

Resultado

ezgif.com-gif-maker

 

 

Esse e todos os exemplos deste blog encontram-se disponíveis no GitHub.

icongithub

7 comentários em “BadgeView – Xamarin.Forms

  1. Juliano, como eu faria para mostrar esse badge em cima de uma botão ou de uma small image, tipo ícone ou um png de 48 X 48?

    Curtir

    1. Olá Paulo,

      Uma alternativa é você criar o seu botão utilizando um StackLayout com GestureRecognizers para realizar o click. E dentro dele adicionar a badge.

      Espero ter ajudado. Abraço

      Curtir

  2. Então, o badge está ficando fora do botão. Se eu aumento o width do botão o badge é jogado mais ao lado. O que devo alterar para ter o badge em cima do botão, não quero aqui dizer que sou novo e por isso tenho dúvida, mas não estou conseguindo utilizar corretamente. Tentei incluir no meu projeto e lá não funciona, não dá erro mas não aparece nada. É só isso, mas o seu exemplo é exatamente o que eu necessito, exatamente. Me desculpa mas falta alguma coisa ainda.

    Curtir

    1. Olá Paulo,

      O exemplo que encontra-se no Github está funcionando, eu escrevi um código que faz a mesma coisa do exemplo, a diferença que é um botão que eu criei com um StackLayout.

      Se preferir baixe o projeto do Github e substitua o xaml


      <?xml version="1.0" encoding="utf-8" ?>
      <ContentPage xmlns="http://xamarin.com/schemas/2014/forms&quot;
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml&quot;
      xmlns:local="clr-namespace:BadgeView"
      x:Class="BadgeView.MainPage">
      <ContentPage.Content>
      <StackLayout BackgroundColor="DarkGray"
      HeightRequest="35" VerticalOptions="Center">
      <StackLayout.GestureRecognizers>
      <TapGestureRecognizer Tapped="AddNotification"/>
      </StackLayout.GestureRecognizers>
      <StackLayout Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center">
      <Label HorizontalTextAlignment="Center" Text="Notifications" FontSize="18" TextColor="White"/>
      <local:Badge x:Name="BadgeNotifications" BoxColor="red"
      WidthRequest="18" HeightRequest="18"
      VerticalOptions="Center" HorizontalOptions="Center">
      <x:Arguments>
      <x:Double>30</x:Double>
      <x:Double>10</x:Double>
      </x:Arguments>
      </local:Badge>
      </StackLayout>
      </StackLayout>
      </ContentPage.Content>
      </ContentPage>

      view raw

      MainPage.xaml

      hosted with ❤ by GitHub

      Espero ter ajudado.

      Curtir

  3. Tentei incluir as classes e o badge(xaml) e não estou conseguindo fazer funcionar. É como se ele não reconhecesse a classe Badge no PCL. Baixei seu exemplo do git e funciona, mas se coloco no meu projeto eu não consigo fazer funcionar. Poderia me ajudar nisso?

    Curtir

  4. Juliano, descobri porque que não estava funcionando no meu projeto. Era por causa disto:

    BoxColor=”red” e eu troquei para isso: BoxColor=”Red” mas no seu exemplo está funcionando e não se porque, mas resolveu no meu. Valeu!!

    Curtir

Deixe um comentário