2using System.ComponentModel;
3using System.Threading.Tasks;
4using System.Windows.Input;
6using Microsoft.Maui.Controls;
7using Microsoft.Maui.Controls.Shapes;
8using Microsoft.Maui.Graphics;
69 private readonly Label badgeLabel;
74 private const double indicatorSize = 10;
78 #region Bindable Properties
84 BindableProperty.Create(
89 propertyChanged: OnTextChanged);
95 BindableProperty.Create(
100 propertyChanged: OnFontSizeChanged);
106 BindableProperty.Create(
111 propertyChanged: OnTextColorChanged);
117 BindableProperty.Create(
122 propertyChanged: OnFontFamilyChanged);
128 BindableProperty.Create(
133 propertyChanged: OnCornerRadiusChanged);
139 BindableProperty.Create(
144 propertyChanged: OnIsIndicatorChanged);
150 BindableProperty.Create(
160 BindableProperty.Create(
165 propertyChanged: OnTextMarginChanged);
255 this.badgeLabel =
new Label
257 HorizontalOptions = LayoutOptions.Center,
258 VerticalOptions = LayoutOptions.Center,
265 this.Content = this.badgeLabel;
267 TapGestureRecognizer TapGesture =
new TapGestureRecognizer();
268 TapGesture.Tapped += this.OnBadgeTapped;
269 this.GestureRecognizers.Add(TapGesture);
274 #region Event Handlers
281 private void OnBadgeTapped(
object? sender, EventArgs e)
283 if (this.
Command?.CanExecute(
null) ==
true)
291 #region Bindable Property Changed Callbacks
299 private static void OnTextMarginChanged(BindableObject bindable,
object oldValue,
object newValue)
301 if (bindable is
Badge Badge && newValue is Thickness NewMargin)
303 Badge.badgeLabel.Margin = NewMargin;
304 Badge.UpdateSizeAndShape();
314 private static void OnTextChanged(BindableObject bindable,
object oldValue,
object newValue)
318 string TextValue = newValue?.ToString() ??
string.Empty;
320 Badge.UpdateVisibility();
322 if (!
Badge.IsIndicator)
324 Badge.badgeLabel.Text = TextValue;
325 _ =
Badge.AnimateBounceAsync();
328 Badge.UpdateSizeAndShape();
338 private static void OnFontSizeChanged(BindableObject bindable,
object oldValue,
object newValue)
342 Badge.badgeLabel.FontSize = (double)newValue;
343 Badge.UpdateSizeAndShape();
350 private static void OnTextColorChanged(BindableObject bindable,
object oldValue,
object newValue)
354 Badge.badgeLabel.TextColor = (Color)newValue;
361 private static void OnFontFamilyChanged(BindableObject bindable,
object oldValue,
object newValue)
365 Badge.badgeLabel.FontFamily = newValue?.ToString();
372 private static void OnCornerRadiusChanged(BindableObject bindable,
object oldValue,
object newValue)
374 if (bindable is
Badge Badge && newValue is
double)
377 Badge.UpdateCornerRadius();
384 private static void OnIsIndicatorChanged(BindableObject bindable,
object oldValue,
object newValue)
388 bool IsIndicatorValue = (bool)newValue;
389 Badge.badgeLabel.Text = IsIndicatorValue ? string.Empty :
Badge.Text;
390 Badge.UpdateSizeAndShape();
391 Badge.UpdateVisibility();
397 #region Private Methods
403 private async Task AnimateBounceAsync()
405 await this.ScaleToAsync(1.2, 50);
406 await this.ScaleToAsync(1.0, 50);
412 private void UpdateVisibility()
416 this.IsVisible =
true;
420 if (
string.IsNullOrEmpty(this.
Text))
422 this.IsVisible =
false;
424 else if (
int.TryParse(this.
Text, out
int Count))
426 this.IsVisible = Count > 0;
430 this.IsVisible =
true;
441 private void UpdateCornerRadius()
447 else if (this.Height > 0)
449 if (!
string.IsNullOrEmpty(this.
Text) && this.
Text.Length == 1)
451 this.StrokeShape =
new Ellipse();
456 double EffectiveCornerRadius = Math.Min(this.
CornerRadius, this.Height / 2);
465 private void UpdateSizeAndShape()
469 this.badgeLabel.Text =
string.Empty;
470 this.HeightRequest = indicatorSize;
471 this.WidthRequest = indicatorSize;
476 string TextValue = this.Text ??
string.Empty;
477 if (TextValue.Length == 1)
479 Size Request = this.badgeLabel.Measure(
double.PositiveInfinity,
double.PositiveInfinity);
480 double DesiredWidth = Request.Width + this.
TextMargin.HorizontalThickness;
481 double DesiredHeight = Request.Height + this.
TextMargin.VerticalThickness;
482 double Diameter = Math.Max(DesiredWidth, DesiredHeight);
485 this.WidthRequest = Diameter;
486 this.HeightRequest = Diameter;
489 this.StrokeShape =
new Ellipse();
493 this.WidthRequest = -1;
494 this.HeightRequest = -1;
495 this.UpdateCornerRadius();
501 protected override void OnBindingContextChanged()
503 base.OnBindingContextChanged();
506 this.UpdateVisibility();
507 this.UpdateSizeAndShape();
511 protected override void OnSizeAllocated(
double width,
double height)
513 base.OnSizeAllocated(width, height);
516 this.UpdateCornerRadius();
523 Size Request = this.badgeLabel.Measure(
double.PositiveInfinity,
double.PositiveInfinity);
524 double DesiredWidth = Math.Max(Request.Width +
this.TextMargin.HorizontalThickness, height);
527 if (width < DesiredWidth)
529 this.WidthRequest = DesiredWidth;
Represents a badge control that displays a short text (e.g., a notification count) or a simple indica...
double CornerRadius
Gets or sets the corner radius of the badge.
static readonly BindableProperty TextProperty
Backing store for the Text property.
double FontSize
Gets or sets the font size of the badge text.
static readonly BindableProperty CommandProperty
Backing store for the Command property.
static readonly BindableProperty CornerRadiusProperty
Backing store for the CornerRadius property.
static readonly BindableProperty FontFamilyProperty
Backing store for the FontFamily property.
string Text
Gets or sets the text displayed on the badge.
static readonly BindableProperty IsIndicatorProperty
Backing store for the IsIndicator property.
Badge()
Initializes a new instance of the Badge class.
static readonly BindableProperty TextMarginProperty
Backing store for the TextMargin property.
Color TextColor
Gets or sets the color of the badge text.
bool IsIndicator
Gets or sets a value indicating whether the badge is displayed as an indicator.
ICommand Command
Gets or sets the command to be executed when the badge is tapped.
static readonly BindableProperty TextColorProperty
Backing store for the TextColor property.
static readonly BindableProperty FontSizeProperty
Backing store for the FontSize property.
Thickness TextMargin
Gets or sets the margin for the badge text.
string FontFamily
Gets or sets the font family of the badge text.