Adding our touch events

Adding touch events will be used to change the rating to the desired rating. Open RatingView and let's add the methods we need to get our control to accept touch events by adding the following inside the main class:

override var canBecomeFirstResponder: Bool {
return shouldBecomeFirstResponder
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
if self.isEnabled {
super.beginTracking(touch, with: event)
if (shouldBecomeFirstResponder && self.isFirstResponder) {
becomeFirstResponder()
}
handle(with: touch)
return true
}
else { return false }
}

Then, add the following into the private extension:

func handle(with touch: UITouch) {
let cellWidth = self.bounds.size.width / CGFloat(totalStars)
let location = touch.location(in: self)
var value = location.x / cellWidth

if (value + 0.5 < CGFloat(ceilf(Float(value)))) {
value = floor(value) + 0.5
}
else {
value = CGFloat(ceilf(Float(value)))
}

updateRating(with: value)
}
// Update Rating
func updateRating(with value:CGFloat) {
if (self.rating != value && value >= 0 && value <= CGFloat(totalStars)) {
self.rating = value
setNeedsDisplay()
}
}

The following code is used to handle touch. First, we set the canBecomeFirstResponder variable. Next, we have the beginTracking(touch:event:). In this method, we set whether our control can accept touch events. If the control is enabled, then we allow touches, and we call the handle() method and pass it the UITouch location. Let's discuss the handle() method.

In our handle method, we start with three variables. We first get the width of the entire rating view. Next, we get the value of the touch location, then finally we take the x value of the location and divide it by the width. We then check the value, figure out whether it is less than 0.5 or greater than 0.5, and round appropriately. Last, we update the rating with the value we calculate.

In the updateRating(value:) method, we check to make sure that our value is not equal to the current value and whether the value is greater than zero and less than the total number of stars. If these conditions pass, then we set the rating to the new value and call the setNeedsDisplay() method. This method makes sure that our control is redrawn.

Open RestaurantDetailsViewController and in the createRating() method, add the following:

ratingView.isEnabled = true

We now have a rating, and by setting the rating to 3.5, we should now see 3.5 stars. We also set the isEnabled value to true, which means we can touch and change the rating. If we set it to false, then the value cannot change. In the restaurant details, we want to turn off touch, but in the ReviewFormViewController we want that to be enabled. You can play with this, and when done set the isEnable value to false and remove the rating.

We set the rating later in the book when we start saving reviews:

You can now change the rating from 3.5 to 4.5 by tapping on the view. Now that we have this set up, let's get our review form set up.