Step 2- Make a folder named Controls and create a file named CustomRatingBar.cs, In CustomRatingBar, make some bindable property as in the following code:
namespace RatingBarDemo.Controls
{
class CustomRatingBar:View
{
public event EventHandler<float> RatingChanged;
public event EventHandler Tapped;
public static BindableProperty IsSmallStyleProperty = BindableProperty.Create("IsSmallStyle", typeof(bool),
typeof(CustomRatingBar), false);
public bool IsSmallStyle
{
get { return (bool)GetValue(IsSmallStyleProperty); }
set { SetValue(IsSmallStyleProperty, value); }
}
public static BindableProperty IsReadonlyProperty = BindableProperty.Create("IsReadonly", typeof(bool), typeof(CustomRatingBar), true);
public bool IsReadonly
{
get { return (bool)GetValue(IsReadonlyProperty); }
set { SetValue(IsReadonlyProperty, value); }
}
public static BindableProperty MaxStarsProperty = BindableProperty.Create("MaxStars", typeof(int), typeof(CustomRatingBar), 5);
public int MaxStars
{
get { return (int)GetValue(MaxStarsProperty); }
set { SetValue(MaxStarsProperty, value); }
}
public static BindableProperty RatingProperty = BindableProperty.Create("Rating", typeof(float), typeof(CustomRatingBar), 0f);
public float Rating
{
get { return (float)GetValue(RatingProperty); }
set { SetValue(RatingProperty, value); OnPropertyChanged("Rating"); }
}
public static BindableProperty StepSizeProperty = BindableProperty.Create("StepSize", typeof(float), typeof(CustomRatingBar), 0.5f);
public float StepSize
{
get { return (float)GetValue(StepSizeProperty); }
set { SetValue(StepSizeProperty, value); }
}
public void OnRatingChanged(float rating)
{
if (RatingChanged != null)
RatingChanged.Invoke(this, rating);
}
public Color GetFillColor()
{
return Rating == 0 ? Color.Gray : Rating <= 2 ? Colors.StarRed : Rating <= 3 ? Colors.StarOrange : Rating <= 4 ? Colors.StarYellow : Colors.StarGreen;
}
public void OnTapped()
{
if (Tapped != null)
Tapped.Invoke(this, null);
}
}
}
Step 3(optional)- Make a Helper class for different colour requisites, below code use.
namespace RatingBarDemo.Helpers
{
class Colors
{
public static readonly Color StarRed = Color.FromHex("#E41E26");
public static readonly Color StarOrange = Color.FromHex("#FF6817");
public static readonly Color StarYellow = Color.FromHex("#FFDE17");
public static readonly Color StarGreen = Color.FromHex("#3AB54A");
}
}
Step 4 - For Android- Now we make a renderer for rating bar in android.
[assembly: ExportRenderer(typeof(CustomRatingBar), typeof(RatingBarRenderer))]
namespace RatingBarDemo.Droid.Renderers
{
class RatingBarRenderer:ViewRenderer<CustomRatingBar, RatingBar>
{
CustomRatingBar element;
RatingBar ratingBar;
protected override void OnElementChanged(ElementChangedEventArgs<CustomRatingBar> e)
{
if (e.NewElement == null)
return;
element = Element as CustomRatingBar;
base.OnElementChanged(e);
if (e.NewElement == null || Control != null)
return;
SetStars();
}
public void SetStars()
{
ratingBar = new RatingBar(Forms.Context, null, element.IsSmallStyle ? Android.Resource.Attribute.RatingBarStyleSmall
: Android.Resource.Attribute.RatingBarStyle)
{
StepSize = 1.0f,
NumStars = element.MaxStars,
Rating = element.Rating,
};
RegisterEvents(element.IsReadonly);
LayerDrawable drawable = (LayerDrawable)ratingBar.ProgressDrawable;
SetDefaultColor(drawable);
SetFillColor(drawable);
SetNativeControl(ratingBar);
}
private void RegisterEvents(bool isReadOnly)
{
ratingBar.RatingBarChange -= Control_RatingBarChange;
if (!isReadOnly)
{
ratingBar.RatingBarChange += Control_RatingBarChange;
}
}
private void SetFillColor(LayerDrawable drawable)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
Android.Support.V4.Graphics.Drawable.DrawableCompat.SetTint(drawable, element.GetFillColor().ToAndroid());
}
else
{
drawable.GetDrawable(2).SetColorFilter(element.GetFillColor().ToAndroid(),
Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
private void SetDefaultColor(LayerDrawable drawable)
{
drawable.GetDrawable(0).SetColorFilter(Android.Graphics.Color.Gray,
Android.Graphics.PorterDuff.Mode.SrcAtop);
}
private void Control_RatingBarChange(object sender, RatingBar.RatingBarChangeEventArgs e)
{
element.OnRatingChanged(e.Rating);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals(CustomRatingBar.RatingProperty.PropertyName))
{
RegisterEvents(false);
ratingBar.Rating = element.Rating;
RegisterEvents(element.IsReadonly);
SetFillColor((LayerDrawable)ratingBar.ProgressDrawable);
}
}
}
}
Step 5 - For Android- Now creating a renderer for iOS for rating bar as well.
[assembly: ExportRenderer(typeof(CustomRatingBar), typeof(RatingBarRenderer))]
namespace RatingBarDemo.iOS.Renderers
{
class RatingBarRenderer:ViewRenderer<CustomRatingBar, UIView>
{
const string IconStarBlank = "ic_star_blank.png";
const string IconStarYellow = "ic_star_yellow.png";
const string IconStarGreen = "ic_star_green.png";
const string IconStarOrange = "ic_star_orange.png";
const string IconStarRed = "ic_star_red.png";
UIView rateView;
UIButton oneStar, twoStar, threeStar, fourStar, fiveStar;
float starSize;
CustomRatingBar element;
protected override void OnElementChanged(ElementChangedEventArgs<CustomRatingBar> e)
{
base.OnElementChanged(e);
element = Element as CustomRatingBar;
if (element == null)
return;
InitializeButton();
SetTouchEvents(element.IsReadonly);
rateView = new UIView()
{
};
if (element.IsSmallStyle)
{
starSize = 15;
rateView.Frame = new CGRect(0, 0, 95, 15);
SetRatingBarSmall();
AddStarInView();
if (element.Rating >= 0)
ShowRatingBar();
}
else
{
starSize = 30;
rateView.Frame = new CGRect(0, 0, 170, 30);
SetRatingBarDefault();
AddStarInView();
ShowRatingBar();
}
SetNativeControl(rateView);
var tapGesture = new UITapGestureRecognizer(OnRateViewTapped);
rateView.AddGestureRecognizer(tapGesture);
}
private void OnRateViewTapped()
{
element.OnTapped();
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals(CustomRatingBar.RatingProperty.PropertyName))
{
ShowRatingBar();
}
else if (e.PropertyName.Equals(CustomRatingBar.IsReadonlyProperty.PropertyName))
{
SetTouchEvents(element.IsReadonly);
}
}
// rating bar bind with value;
private void ShowRatingBar()
{
if (Element.Rating <= 0)
SetBlankStarRating();
else if (Element.Rating <= 1)
SetOneStarRating();
else if (Element.Rating <= 2)
SetTwoStarRating();
else if (Element.Rating <= 3)
SetThreeStarRating();
else if (Element.Rating <= 4)
SetFourStarRating();
else if (Element.Rating <= 5)
SetFiveStarRating();
}
// button initialize
private void InitializeButton()
{
oneStar = UIButton.FromType(UIButtonType.Custom);
oneStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
twoStar = UIButton.FromType(UIButtonType.Custom);
twoStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
threeStar = UIButton.FromType(UIButtonType.Custom);
threeStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fourStar = UIButton.FromType(UIButtonType.Custom);
fourStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fiveStar = UIButton.FromType(UIButtonType.Custom);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
void OneStar_TouchUpInside(object sender, EventArgs e)
{
element.OnRatingChanged(1);
}
void TwoStar_TouchUpInside(object sender, EventArgs e)
{
element.OnRatingChanged(2);
}
void ThreeStar_TouchUpInside(object sender, EventArgs e)
{
element.OnRatingChanged(3);
}
void FourStar_TouchUpInside(object sender, EventArgs e)
{
element.OnRatingChanged(4);
}
void FiveStar_TouchUpInside(object sender, EventArgs e)
{
element.OnRatingChanged(5);
}
private void SetTouchEvents(bool isReadOnly)
{
oneStar.TouchUpInside -= OneStar_TouchUpInside;
twoStar.TouchUpInside -= TwoStar_TouchUpInside;
threeStar.TouchUpInside -= ThreeStar_TouchUpInside;
fourStar.TouchUpInside -= FourStar_TouchUpInside;
fiveStar.TouchUpInside -= FiveStar_TouchUpInside;
if (isReadOnly == false)
{
oneStar.TouchUpInside += OneStar_TouchUpInside;
twoStar.TouchUpInside += TwoStar_TouchUpInside;
threeStar.TouchUpInside += ThreeStar_TouchUpInside;
fourStar.TouchUpInside += FourStar_TouchUpInside;
fiveStar.TouchUpInside += FiveStar_TouchUpInside;
}
}
// rating bar size
private void SetRatingBarSmall()
{
//int x = (int)(App.ScreenSize.Width - ratingBarWidth) / 2;
int x = 0;
oneStar.Frame = new CGRect(x, 0, starSize, starSize);
twoStar.Frame = new CGRect(x = x + 20, 0, starSize, starSize);
threeStar.Frame = new CGRect(x = x + 20, 0, starSize, starSize);
fourStar.Frame = new CGRect(x = x + 20, 0, starSize, starSize);
fiveStar.Frame = new CGRect(x = x + 20, 0, starSize, starSize);
}
private void SetRatingBarDefault()
{
//int x = (int)(App.ScreenSize.Width - ratingBarWidth) / 2;
int x = 0;
oneStar.Frame = new CGRect(x, 0, starSize, starSize);
twoStar.Frame = new CGRect(x = x + 35, 0, starSize, starSize);
threeStar.Frame = new CGRect(x = x + 35, 0, starSize, starSize);
fourStar.Frame = new CGRect(x = x + 35, 0, starSize, starSize);
fiveStar.Frame = new CGRect(x = x + 35, 0, starSize, starSize);
}
private void AddStarInView()
{
rateView.AddSubview(oneStar);
rateView.AddSubview(twoStar);
rateView.AddSubview(threeStar);
rateView.AddSubview(fourStar);
rateView.AddSubview(fiveStar);
}
private void SetBlankStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
private void SetOneStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarRed), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
private void SetTwoStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarRed), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarRed), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
private void SetThreeStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarOrange), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarOrange), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarOrange), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
private void SetFourStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarYellow), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarYellow), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarYellow), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarYellow), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarBlank), UIControlState.Normal);
}
private void SetFiveStarRating()
{
oneStar.SetImage(UIImage.FromFile(IconStarGreen), UIControlState.Normal);
twoStar.SetImage(UIImage.FromFile(IconStarGreen), UIControlState.Normal);
threeStar.SetImage(UIImage.FromFile(IconStarGreen), UIControlState.Normal);
fourStar.SetImage(UIImage.FromFile(IconStarGreen), UIControlState.Normal);
fiveStar.SetImage(UIImage.FromFile(IconStarGreen), UIControlState.Normal);
}
}
}
Step 6 - Now u can use the rating bar in XAML files as:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="RatingBarDemo.Views.RatingBarPage"
xmlns:uc="clr-namespace:RatingBarDemo.Controls" >
<uc:CustomRatingBar x:Name="customRatingBar" MaxStars="5"
RatingChanged="OnRatingChanged" IsReadonly="false" />
</ContentPage>