Skip to content

Instantly share code, notes, and snippets.

@seba47
Forked from rudyryk/Badge.cs
Created March 4, 2016 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seba47/2a61f80b5251e46a8707 to your computer and use it in GitHub Desktop.
Save seba47/2a61f80b5251e46a8707 to your computer and use it in GitHub Desktop.
C# — Xamarin.Forms custom simple badge view + rounded box view via custom renderer
//
// 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 <alexey.rudy@gmail.com>
//
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
}
}
//
// 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 <alexey.rudy@gmail.com>
//
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); }
}
}
}
//
// 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 <alexey.rudy@gmail.com>
//
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);
}
}
}
//
// 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 <alexey.rudy@gmail.com>
//
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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment