Before talking about the screens implementation itself, some theory about VoiceOver itself.
VoiceOver is an assistive technology that is used by blind and partially sighted users on iOS and MacOS operating systems to read screen the screen content as it changes. If an application is setup correctly with accessibility in mind, VO users should have the same (if not a better) experience than non-VO users.
Some theory about the UIAccessibility framework itself, any UIView from the iOS UIKit library has a lot of properties related to accessibility, for now, we will describe only the four main that you will use mostly in all your iOS apps:
– accessibilityLabel: this property is the text that will be effectively read by the VoiceOver text to speech when the user focusses the view element with the VoiceOver engine turned on. For components such as UILabel, modifying the text property will automatically set the accessibilityLabel to the same value.
– accessibilityValue: a text that will be read as an additional context description after the accessibilityLabel has been read.
– accessibilityHint: a hint that will be read as an additional context description only if the user turned it on in device accessibility settings. Thus it should not be used if it provides critical info.
– accessibilityTraits: some enum that specify the semantics of the view element e.g. it can be Header (for example for a label above table view), button,
In addition, you can disable the accessibility for any view element by setting its isAccessibilityElement property to false.
Another trick that we will not use in this sample app is grouping elements and specifying the read order of the elements inside (using accessibilityElements and accessibilityFrame).
That is meant to be used if you have a bunch of elements and you thing the accessibility experience would be better by grouping the elements into a single one.
Here we will take the example of the following view hierarchy:
You must first set the accessibilityFrame of the container view as the union of the child frames e.g.
Then, if needed, you can customise the read order of the inner elements:
An interesting alternative is to use the accessibility label:
containerView |
|—child1 |—child2
containerView.accessibilityFrame = child1.frame.union(child2.frame)
containerView.isAccessibilityEnabled = true child1.isAccessibilityEnabled = false
child2.isAccessibilityEnabled = false
containerView.accessibilityElements = [child1, child2]
containerView.accessibilityLabel = child1.accessibilityLabel + “, ” + child2.accessibilityLabel