Previous part: Using Icon Fonts in MAUI .NET 9 [GamesCatalog] - Part 7
Step 1. Let's create a component named RatingBar.
![RatingBar]()
Step 2. Let's define the initial code for RatingBar.xaml.
<VerticalStackLayout
x:Class="GamesCatalog.Components.RatingBar"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Icons="clr-namespace:GamesCatalog.Resources.Fonts"
x:Name="This">
</VerticalStackLayout>
We will reference our icon font and define a variable to control the visibility of the component.
Step 2.1. Let's create a hidden label to expose the rating variable so we can interact with its value.
<Label IsVisible="false" Text="{Binding Source={x:Reference this}, Path=Rate}" />
Step 2.2. Let's create a grid to allocate a rating from 1 to 10.
<Grid Margin="0,10,0,10" HorizontalOptions="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
Step 2.3. Let's create the labels that will be linked to the rating inside the grid.
<Label
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star1Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star1Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="1"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star2Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star2Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="2"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star3Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star3Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="3"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star4Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star4Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="4"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star5Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star5Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="5"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star6Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star6Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="6"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star7Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star7Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="7"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star8Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star8Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="8"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star9Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star9Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
<Label
Grid.Column="9"
Margin="0,0,3,0"
FontFamily="FontAwesomeIcons"
FontSize="20"
HorizontalOptions="Center"
Text="{x:Static Icons:IconFont.Star}"
TextColor="{Binding Source={x:Reference this}, Path=Star10Color}">
<Label.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={x:Reference this}, Path=Star10Command}"
CommandParameter="1" />
</Label.GestureRecognizers>
</Label>
Basically, we have 10 star icons, and we will control their color and set the rating via the tap command on each one.
Note. We will use an icon that we already have available in our icon font, but it would also be possible to use images by using an <Image> object, changing which image to load according to the tap command on each one.
Step 3. In RatingBar.xaml.cs, let's define the colors for the ratings.
static readonly Color DefaultColor = Color.FromArgb("#ACACAC");
static readonly Color HigthRatingColor = Color.FromArgb("#2B9B74");
static readonly Color MediumRatingColor = Color.FromArgb("#CBB52A");
static readonly Color LowRatingColor = Color.FromArgb("#9B2B2B");
Step 3.1. The color variables for each star, with their initial values and their binding to the front end.
private Color star1Color = DefaultColor, star2Color = DefaultColor, star3Color = DefaultColor,
star4Color = DefaultColor, star5Color = DefaultColor, star6Color = DefaultColor,
star7Color = DefaultColor, star8Color = DefaultColor, star9Color = DefaultColor,
star10Color = DefaultColor;
public Color Star1Color
{
get => star1Color;
set { star1Color = value; OnPropertyChanged(nameof(Star1Color)); }
}
public Color Star2Color
{
get => star2Color;
set { star2Color = value; OnPropertyChanged(nameof(Star2Color)); }
}
public Color Star3Color
{
get => star3Color;
set { star3Color = value; OnPropertyChanged(nameof(Star3Color)); }
}
public Color Star4Color
{
get => star4Color;
set { star4Color = value; OnPropertyChanged(nameof(Star4Color)); }
}
public Color Star5Color
{
get => star5Color;
set { star5Color = value; OnPropertyChanged(nameof(Star5Color)); }
}
public Color Star6Color
{
get => star6Color;
set { star6Color = value; OnPropertyChanged(nameof(Star6Color)); }
}
public Color Star7Color
{
get => star7Color;
set { star7Color = value; OnPropertyChanged(nameof(Star7Color)); }
}
public Color Star8Color
{
get => star8Color;
set { star8Color = value; OnPropertyChanged(nameof(Star8Color)); }
}
public Color Star9Color
{
get => star9Color;
set { star9Color = value; OnPropertyChanged(nameof(Star9Color)); }
}
public Color Star10Color
{
get => star10Color;
set { star10Color = value; OnPropertyChanged(nameof(Star10Color)); }
}
Step 3.2. The function will set their color according to the rating.
protected void BuildRatingBar(int rate)
{
switch (rate)
{
case 1:
Star2Color = Star3Color = Star4Color = Star5Color = Star6Color =
Star7Color = Star8Color = Star9Color = Star10Color = DefaultColor;
Star1Color = LowRatingColor;
break;
case 2:
Star3Color = Star4Color = Star5Color = Star6Color = Star7Color =
Star8Color = Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = LowRatingColor;
break;
case 3:
Star4Color = Star5Color = Star6Color = Star7Color = Star8Color =
Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = LowRatingColor;
break;
case 4:
Star5Color = Star6Color = Star7Color = Star8Color = Star9Color =
Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = LowRatingColor;
break;
case 5:
Star6Color = Star7Color = Star8Color = Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color = MediumRatingColor;
break;
case 6:
Star7Color = Star8Color = Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color =
Star6Color = MediumRatingColor;
break;
case 7:
Star8Color = Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color =
Star6Color = Star7Color = MediumRatingColor;
break;
case 8:
Star9Color = Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color =
Star6Color = Star7Color = Star8Color = HigthRatingColor;
break;
case 9:
Star10Color = DefaultColor;
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color =
Star6Color = Star7Color = Star8Color = Star9Color = HigthRatingColor;
break;
case 10:
Star1Color = Star2Color = Star3Color = Star4Color = Star5Color =
Star6Color = Star7Color = Star8Color = Star9Color = Star10Color = HigthRatingColor;
break;
}
}
Step 3.3. The variable is responsible for exposing the rating value; we will call the function that defines the star colors whenever this value changes.
public static readonly BindableProperty RateProperty = BindableProperty.Create(
propertyName: nameof(Rate),
returnType: typeof(int),
declaringType: typeof(RatingBar),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay
);
public int Rate
{
get
{
int _rate = (int)GetValue(RateProperty);
BuildRatingBar(_rate);
return (int)GetValue(RateProperty);
}
set => SetValue(RateProperty, value);
}
Step 3.4. The tap commands for each star will set the rating value.
[RelayCommand]
private void Star1() => Rate = 1;
[RelayCommand]
private void Star2() => Rate = 2;
[RelayCommand]
private void Star3() => Rate = 3;
[RelayCommand]
private void Star4() => Rate = 4;
[RelayCommand]
private void Star5() => Rate = 5;
[RelayCommand]
private void Star6() => Rate = 6;
[RelayCommand]
private void Star7() => Rate = 7;
[RelayCommand]
private void Star8() => Rate = 8;
[RelayCommand]
private void Star9() => Rate = 9;
[RelayCommand]
private void Star10() => Rate = 10;
This way, we have a reusable component with a grid containing 10 horizontal stars, which is responsible for setting a rating from 1 to 10.
Step 4. Let's place the rating bar right above the confirmation button.
![Confirmation button]()
Code
<Border
Margin="0,5,0,5"
Padding="5"
Background="Transparent"
HorizontalOptions="Center"
IsVisible="{Binding RatingBarIsVisible}"
Stroke="{StaticResource SecondaryElementColor}"
StrokeShape="RoundRectangle 10">
<Components:RatingBar Rate="{Binding Rate}" />
</Border>
Step 5. In AddGameVM.cs, define the variables RatingBarIsVisible and Rate.
private int? rate = 0;
public int? Rate
{
get => rate;
set
{
if (RatingBarIsVisible)
ConfirmIsVisible = true;
SetProperty(ref rate, value);
}
}
private bool ratingBarIsVisible = false;
public bool RatingBarIsVisible
{
get => ratingBarIsVisible;
set => SetProperty(ref ratingBarIsVisible, value);
}
The Rate variable will control the visibility of the confirmation button for a game that has been played and rated.
Step 5.1. Let's define the default rating and the visibility of the rating bar in the commands.
![Commands]()
And that’s how we have our functional rating bar on the app screen.
![App screen]()
In the next step, we will create a local database.
Code on git: GamesCatalog git