Create a Star Rating view in SwiftUI?
In this post, we will be creating a Custom Star Rating View, where we can give a rating from 1 to 5 stars. In this example we will using a “Star” but alternatively you can use heart or any other image too.
To illustrate, we’ll create a star rating display that allows users to touch photos to submit values between 1 and 5. Although we could make this view simple enough to work for our specific use case, it is always preferable to offer flexibility when necessary so that it may be re-utilised in other applications as well. In this case, we will create six adjustable properties:-
• An option label for our rating view.
• The maximum number of stars. We’ll set it to 5, but in some other cases, you might need 10.
• An On Image, which will be shown when the rating/star is clicked/tapped.
• An Off Image, which will be shown when the rating/star is not clicked/tapped. This is an optional image, because eventually we will be using on/off colors.
• On color, we will be using yellow color, if the star is clicked.
• Off color, we will be using gray color, if the star is not clicked.
We will be using @Binding property to store user’s rating.
So, create a RatingView and start coding :-
@Binding var rating: Int
var label = "Tap on the Star to rate"
var maxRating = 5
var offImage: Image?
var onImage = Image(systemName: "star.fill")
var offColor = Color.gray
var onColor = Color.yellow
How to show stars in Rating View in Swift UI?
The logic for selecting which image to display is basic, but it is ideal to make its own function to make our code more readable and re-usable. The logic is as under:-
- If the passed-in number is larger than the existing rating, return the off image. However, if we don’t have any off image we will nil coealsce it to the on image.
- If the passed-in number is equal to or less than the existing rating, the on image is returned.
We will add the method at the end of our view :
func image(for number: Int) -> Image {
if number > rating {
return offImage ?? onImage
} else {
return onImage
}
}
Now we will add it to our body view as under:-
VStack {
Spacer()
Text(label)
.font(.system(size: 30))
Spacer()
HStack{
ForEach(1..<maxRating + 1, id:\.self){number in
image(for: number)
.font(.system(size: 45))
.foregroundColor(number>rating ? offColor : onColor)
.onTapGesture {
rating = number
}
}
}
Spacer()
}