UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Project 15: Day 75: Better accessibility for RatingView

Forums > 100 Days of SwiftUI

When adding accessibilty to the rating view I felt there might be a better way to do it. Instead of keeping each star as an individual button I thought it might make more sense to access them as a set.

You can use accessibilityAdjustableAction() to give actions to swipe directions and basically turn any view into an adjustable control.

Here's my full code for RatingView:

import SwiftUI

struct RatingView: View {
    @Binding var rating: Int16?

    var label = ""
    var maximumRating = 5
    var offImage: Image?
    var onImage = Image(systemName: "star.fill")
    var offColor = Color.gray
    var onColor = Color.yellow

    // Special rating string for voice over
    var ratingString: String { 
        if let rating = rating {
            return "\(rating) star\(rating == 1 ? "" : "s")"
        }
        return "No star rating applied"  // A helpful note for when the rating is nil
    }

    var body: some View {
        HStack {
            if label.isEmpty == false {
                Text(label)
            }
            ForEach(1..<maximumRating + 1) { number in
                self.image(for: number)
                    .foregroundColor(number > (self.rating ?? 0) ? self.offColor : self.onColor)
                    .onTapGesture {
                        self.rating = Int16(number)
                    }
            }
        }
        .accessibilityElement(children: .ignore)  // All views inside the HStack are ignored for accessibility
        .accessibility(label: Text(label))  // Label added here
        .accessibility(value: Text(ratingString)) // Value added here
        .accessibilityAdjustableAction() { direction in  // This function allows you to run code based swipes up or down
            guard let rating = self.rating else {
                self.rating = 3
                return
            }
            if direction == .increment {
                self.rating = min(rating + 1, 5)
            } else if direction == .decrement {
                self.rating = max(rating - 1, 0)
            }
        }
    }

    func image(for number: Int) -> Image {
        if number > (rating ?? 0) {
            return offImage ?? onImage
        } else {
            return onImage
        }
    }
}

struct RatingView_Previews: PreviewProvider {
    static var previews: some View {
        RatingView(rating: .constant(4))
    }
}

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.