Last active
September 5, 2024 09:51
-
-
Save rudyryk/8cbe067a1363b45351f6 to your computer and use it in GitHub Desktop.
C# — Xamarin.Forms custom simple badge view + rounded box view via custom renderer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Badge.cs | |
// Created by Alexey Kinev on 19 Jan 2015. | |
// | |
// Licensed under The MIT License (MIT) | |
// http://opensource.org/licenses/MIT | |
// | |
// Copyright (c) 2015 Alexey Kinev <[email protected]> | |
// | |
using System; | |
using Xamarin.Forms; | |
namespace ZeroFiveBit.Forms.Basic | |
{ | |
/// <summary> | |
/// Badge. | |
/// </summary> | |
public class Badge : AbsoluteLayout | |
{ | |
/// <summary> | |
/// The text property. | |
/// </summary> | |
public static readonly BindableProperty TextProperty = | |
BindableProperty.Create("Text", typeof(String), typeof(Badge), ""); | |
/// <summary> | |
/// The box color property. | |
/// </summary> | |
public static readonly BindableProperty BoxColorProperty = | |
BindableProperty.Create("BoxColor", typeof(Color), typeof(Badge), Color.Default); | |
/// <summary> | |
/// The text. | |
/// </summary> | |
public string Text | |
{ | |
get { return (string)GetValue(TextProperty); } | |
set { SetValue(TextProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets the color of the box. | |
/// </summary> | |
public Color BoxColor | |
{ | |
get { return (Color)GetValue(BoxColorProperty); } | |
set { SetValue(BoxColorProperty, value); } | |
} | |
/// <summary> | |
/// The box. | |
/// </summary> | |
protected RoundedBox Box; | |
/// <summary> | |
/// The label. | |
/// </summary> | |
protected Label Label; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="ZeroFiveBit.Forms.Basic.Badge"/> class. | |
/// </summary> | |
public Badge(double size, double fontSize) | |
{ | |
HeightRequest = size; | |
WidthRequest = HeightRequest; | |
// Box | |
Box = new RoundedBox { | |
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)); | |
// Hide if no value | |
SetBinding(IsVisibleProperty, new Binding("Text", BindingMode.OneWay, | |
new BadgeVisibleValueConverter(), source: this)); | |
// Default color | |
BoxColor = Color.Red; | |
} | |
} | |
/// <summary> | |
/// Badge visible value converter. | |
/// </summary> | |
class BadgeVisibleValueConverter : IValueConverter | |
{ | |
#region IValueConverter implementation | |
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(); | |
} | |
#endregion | |
} | |
/// <summary> | |
/// Badge width converter. | |
/// </summary> | |
class BadgeWidthConverter : IValueConverter | |
{ | |
/// <summary> | |
/// The width of the base. | |
/// </summary> | |
readonly double baseWidth; | |
/// <summary> | |
/// The width ratio. | |
/// </summary> | |
const double widthRatio = 0.33; | |
public BadgeWidthConverter(double baseWidth) | |
{ | |
this.baseWidth = baseWidth; | |
} | |
#region IValueConverter implementation | |
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) | |
{ | |
var text = value as string; | |
if ((text != null) && (text.Length > 1)) | |
{ | |
// We won't measure text length exactly here! | |
// May be we should, but it's too tricky. So, | |
// we'll just approximate new badge width as | |
// linear function from text legth. | |
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(); | |
} | |
#endregion | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RoundedBox.cs | |
// Created by Alexey Kinev on 19 Jan 2015. | |
// | |
// Licensed under The MIT License (MIT) | |
// http://opensource.org/licenses/MIT | |
// | |
// Copyright (c) 2015 Alexey Kinev <[email protected]> | |
// | |
using System; | |
using Xamarin.Forms; | |
namespace ZeroFiveBit.Forms.Basic | |
{ | |
public class RoundedBox : BoxView | |
{ | |
/// <summary> | |
/// The corner radius property. | |
/// </summary> | |
public static readonly BindableProperty CornerRadiusProperty = | |
BindableProperty.Create("CornerRadius", typeof(double), typeof(RoundedBox), 0.0); | |
/// <summary> | |
/// Gets or sets the corner radius. | |
/// </summary> | |
public double CornerRadius | |
{ | |
get { return (double)GetValue(CornerRadiusProperty); } | |
set { SetValue(CornerRadiusProperty, value); } | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RoundedBoxRenderer_Droid.cs | |
// Created by Alexey Kinev on 26 Apr 2015. | |
// | |
// Licensed under The MIT License (MIT) | |
// http://opensource.org/licenses/MIT | |
// | |
// Copyright (c) 2015 Alexey Kinev <[email protected]> | |
// | |
using System; | |
using System.ComponentModel; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Platform.Android; | |
using Android.Graphics; | |
using ZeroFiveBit.Forms.Basic; | |
using ZeroFiveBit.Forms.Basic.Droid; | |
[assembly: ExportRenderer(typeof(RoundedBox), typeof(RoundedBoxRenderer))] | |
namespace ZeroFiveBit.Forms.Basic.Droid | |
{ | |
public class RoundedBoxRenderer : 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 == RoundedBox.CornerRadiusProperty.PropertyName) | |
{ | |
Invalidate(); | |
} | |
} | |
public override void Draw(Canvas canvas) | |
{ | |
var box = Element as RoundedBox; | |
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); | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RoundedBoxRenderer_iOS.cs | |
// Created by Alexey Kinev on 19 Jan 2015. | |
// | |
// Licensed under The MIT License (MIT) | |
// http://opensource.org/licenses/MIT | |
// | |
// Copyright (c) 2015 Alexey Kinev <[email protected]> | |
// | |
using System; | |
using System.ComponentModel; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Platform.iOS; | |
using ZeroFiveBit.Forms.Basic; | |
using ZeroFiveBit.Forms.Basic.iOS; | |
[assembly: ExportRenderer(typeof(RoundedBox), typeof(RoundedBoxRenderer))] | |
namespace ZeroFiveBit.Forms.Basic.iOS | |
{ | |
public class RoundedBoxRenderer : BoxRenderer | |
{ | |
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e) | |
{ | |
base.OnElementChanged(e); | |
if (Element != null) | |
{ | |
Layer.MasksToBounds = true; | |
UpdateCornerRadius(Element as RoundedBox); | |
} | |
} | |
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) | |
{ | |
base.OnElementPropertyChanged(sender, e); | |
if (e.PropertyName == RoundedBox.CornerRadiusProperty.PropertyName) | |
{ | |
UpdateCornerRadius(Element as RoundedBox); | |
} | |
} | |
void UpdateCornerRadius(RoundedBox box) | |
{ | |
Layer.CornerRadius = (float)box.CornerRadius; | |
} | |
} | |
} | |
How to use it? can someone show an example of implementation? I just learning xamarin forms.
@sportzbee I added the badge to the ToolbarItem for iOS using a custom renderer as explained in this blog post.
By the way, if anyone has been able to do the same for Android, I'm interested, I've googled for a solution without any luck.
How can i use it? I have grid and inside it i have 7 image(Grid.Row="0" Grid.Column="0" and so on) how can i do to show badge each cell? The values that will be shown comes from a method like this(the value to be show is resultado):
decimal realizado = 0;
decimal previsto = 0;
foreach (var item in indItem)
{
var val = item.Nome == "Previsto" ? previsto = item.Valor : realizado = item.Valor;
}
decimal desvio = Math.Abs(previsto - realizado);
if (desvio < 1000)
resultado = Math.Truncate(desvio).ToString();
else
while (desvio >= 1000 && siglas.Count > 0)
{
desvio /= 1000;
resultado = Math.Truncate(desvio) + siglas[0];
siglas.RemoveAt(0);
}
if (CorIndicador == "VERDE")
image.Source = ImageSource.FromResource("Estapar.AppOperacional.Images.faturamento caixa-28.png");
else
{
var pinta = CorIndicador == "VERMELHO" ? image.Source = ImageSource.FromResource("Estapar.AppOperacional.Images.faturamento caixa-26.png") : image.Source = ImageSource.FromResource("Estapar.AppOperacional.Images.faturamento caixa-27.png");
}
label.Text = resultado;
and my xaml is like this
<ContentPage.Content>
<StackLayout Padding="0" Spacing="0" Margin="0">
<Grid x:Name="grd" RowSpacing="1" ColumnSpacing="1" Padding="0" Margin="0" >
<Grid.RowDefinitions>
<RowDefinition Height="1" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image x:Name="imgDesvioFat" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Source="{local:ImageResource Operacional.Images.faturamento caixa-28.png}" Aspect="AspectFill">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="OnDesvioFaturamentoTapReconizerTapped" NumberOfTapsRequired="1"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<!--<Label x:Name="lblFaturamento" Text="" Grid.Row="0" Grid.Column="0" TextColor="White" FontSize="9" FontAttributes="Bold" />-->
<!--</Grid>-->
<Image x:Name="imgTckCancelados" Grid.Row="1" Grid.Column="1" Source="{local:ImageResource Operacinal.Images.tickets cancelados-05.png}" Aspect="AspectFill">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTckCanceladosTapGestureReconizerTapped" NumberOfTapsRequired="1"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
i shown just two images, but i have 7 images and the code is such. How can i show the badge and the value inside with my code?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@jaisont07: Do you have a fix already for the misalignment? I'm facing the same issue