问题
I'm looking to implement something for voiceover users that is similar to how Apple handles the miniplayer in their Music app.
In the miniplayer, there are a number of accessibility elements: the album artwork, the track metadata, the play and forward buttons. When a user first selects an element within the miniplayer, the voiceover reads "Miniplayer; double tap to expand the miniplayer" before giving the label for the element selected. But if you navigate between elements in the miniplayer, it will just give each element's label, trait and hint. It will only provide the Miniplayer (container level) label and hint when you have moved from an element outside the miniplayer to an element inside the miniplayer.
Being able to give this kind of context to voiceover users seems like good UX design, but how is this implemented? I understand how to group elements together by including them in the myItem.accessibilityElements
array, but not how to determine whether the current/previous element that the user has selected is part of the same container.
回答1:
To inform a VoiceOver user that an element has been selected within a container, you could create a class for each kind of element you have in the container (use of generics maybe ???) to override the methods of the UIAccessibilityFocus informal protocol.
Let's take an example assuming that we have only labels in the blue container hereunder (code to be adapted for other kinds of elements) :
Create a class for the labels including a property for the superview it belongs to.
class EltLabel : UILabel { var containerView: UIView? { get { return self.superview } set { } } }
Override the UIAccessibilityFocus informal protocol methods in an extension of the new created class.
extension EltLabel { override open func accessibilityElementDidBecomeFocused() { if self.accessibilityElementIsFocused() { // Actions to be done when the element did become focused. } } override open func accessibilityElementDidLoseFocus() { if self.accessibilityElementIsFocused() { // Actions to be done when the element did lose focus. } } override open func accessibilityElementIsFocused() -> Bool { guard let containerView = self.containerView else { return false } return (self.isDescendant(of: containerView)) ? true : false } }
Don't forget to create outlets with your labels and everything is automatically handled.
class BoutonViewController: UIViewController { @IBOutlet weak var label1: EltLabel! @IBOutlet weak var label2: EltLabel! }
This code snippet to be adapted and included in your code environment will inform the VoiceOver users that they have highlighted an element within a container as desired.
Now, if you want to "determine whether the current/previous element that the user has selected is part of the same container", just add a variable in the view controller that will be incremented/decremented every time an element of the container is focused/unfocused (a boolean variable should be enough).
来源:https://stackoverflow.com/questions/55593761/informing-voiceover-users-that-they-have-highlighted-an-element-within-a-contain