Accessibility in iOS

with VoiceOver

Rinni Swift
Geek Culture

--

Intro

VoiceOver is a screen reader that interacts with objects in your apps so users can drive the interface even if they can’t see it. Ensure that the user interface elements in your apps are accessible and useful.
Apple

Although Apple provides a lot of default accessibility elements in your app — like standard UIKit controls and views — more complex views can cause VoiceOver to not be compatible with your view component. Therefore, it’s important to make sure you’re keeping the user experience in mind when constructing VO; Despite whether or not it’s through interface builder or a protocol implementation.

The purpose of VoiceOver is to convey information from an app’s interface to users with disabilities in order to help them effectively use the app.

Tips and Tricks

Before jumping into the various components of UIAccessibility, let’s go over some initial tips and tricks that will help you use and test VoiceOver features conveniently on your device:

  • Accessibility short cut: Settings > Accessibility > General: Accessibility Short cut
    Select VoiceOver to be able to triple click the side button to toggle the feature on/off.
  • VoiceOver Speed: Settings >Accessibility >VoiceOver > Speaking Rate: and adjust.
    OR
    Toggle the accessibility rotor (two finger twisting motion)> Navigate to Speaking Rate > Swipe up/down with one finger to adjust the speaking rate
  • Native app referencing: I personally like to reference certain iOS apps to make sure that the VO behaviors that I implement are similar to that of Apples design pattern. Some apps I use for reference are:
    - Settings
    - App Store
    - Messages
    - Maps
    - Music
  • A11y: An abbreviation for “accessibility” which came from the shortening of long words by substituting middle letters with the number of middle letters instead. There are 11 letters between the “a” and the “y,” so ‘accessibility’ becomes a11y — https://www.boia.org/blog/what-is-a11y

Table of Contents

UIAccessibility
— isAccessibilityElement
— accessibilityLabel
— accessibilityValue
— accessibilityHint
— accessibilityTrait
— UIAccessibilityElement
UIAccessibilityCustomAction
— UIAccessibilityPostNotification
Accessibility methods & properties
— accessibilityIncrement
— accessibilityDecrement
— accessibilityPerformEscape
— accessibilityActivate
— accessibilityFrameInContainerSpace
— accessibilityViewIsModal

UIAccessibility

A set of methods that provides accessibility information about views and controls in an app’s user interface.
Apple

Standard UIKit controls and views implement the UIAccessibility methods and are accessible to assistive apps by default. However, when creating custom views and controllers, you may need to create an instance of UIAccessibilityElement to interface with accessibility features.

UIAccessibilityElement

A class that implements the UIAccessibility informal protocol. This allows you to set properties and methods to be accessible to assistive apps.

Below is an example of a UIAccessibilityElement instance. Make sure the accessibility element is accessible to the parent view through the accessibilityElements property of the parent view.

Line 3 sets the highlighted frame to the union of the titles and subtitles frame.

Now let’s dive deeper into some common accessibility properties

  • isAccessibilityElement: A Boolean value that indicates whether the element is an accessibility element that an assistive app can access.
    When you don’t want assistive apps to access sub elements in a view, you can set the sub elements isAccessibilityElement to false, or set the views isAccessibilityElement to true.
    If a view isAccessibilityElement is true, assistive apps won’t be able to access the subviews.
  • accessibilityLabel: A succinct label in a localized string that identifies the accessibility element.
    The default value for this property is nil unless the element is a UIKit control, in which case, the value is a label that derives from the control’s title. If the control is an image, i.e. an image inside a UIButton, this label should be set to what the image describes, if the image is play/pause icon, the label should be set to “play” or “pause”. The label should also never contain the control’s type, i.e. a button — “play button”. This is because the accessibilityTrait should contain that information and/or the accessibilityHint.
  • accessibilityValue: A localized string that contains the value of the accessibility element. When an accessibility element has a static label and a dynamic value, set this property to return the value.
    i.e. a UITextField that has the label “Email”, but the users text inside the text field as the accessibility value.
  • accessibilityHint: A localized string that contains a brief description of the result of performing an action on the accessibility element.
    The default value for this property is nil unless the element is a UIKit control, in which case, the value is a system-provided hint that derives from the type of control.
    Set this property to make users more clear as to what their actions will result in.
    Follow these guidelines provided by Apple for setting accessibility hints.
  • accessibilityTrait: The combination of accessibility traits that best characterizes the accessibility element.
    If you implement a custom control or view, you need to select all the accessibility traits that best characterize the object, and combine them with its superclass’s traits (that is, with super.accessibilityTraits) by performing an OR operation.
    Check out the list of accessibilityTraits available here.

accessibilityLabel and accessibilityValue are read separated by a comma, whereas the accessibilityHint and accessibilityLabel && accessibilityValue, are separated by a period. This makes a big difference in the way VO reads out the texts. There is always a longer pause before reading out the a11y hint compared to that of the a11y label and value.

UIAccessibilityCustomAction

An array of custom actions to display along with the built-in actions.

Use custom actions when there is more than one action available. Users would then swipe up and down to switch through the actions.

💡 If you have a custom view with one intended action, look into overriding the accessibilityActivate() method of the custom view which gets triggered when users double tap the element with one finger. I cover this later under Accessibility methods & properties.

Above, we’ve set the scopes accessibilityCustomActions to have a call and email action. As users swipe up and down through actions, the name will be what VO reads, and the selector method will be what gets triggered when the user activates it.

When VO detects that there are custom actions on an element, which is based on the accessibilityCustomActions property, VO would add “Actions available. Swipe up or down to select a custom action. Then, double-tap to activate.” text as the accessibilityHint.

Good to Know 💡: Users with VO enabled can make the “Z” gesture on screen with two fingers which acts as a back/escape action. Simply override the accessibilityPerformEscape() method on the view controller for further customizations — using the term “further customizations” because view controllers have that functionality by default!

UIAccessibilityPostNotification

Posts a notification to assistive apps.

Call UIAccessibility.post(notification:argument:) when you have view components that change very frequently or that appear or disappear.

See the list of notifications here.

UIAccessibility.post(notification: .announcement, argument: "some text")

Once the line above gets triggered, VO will read “some text”.

Accessibility methods & properties

  • accessibilityIncrement() | accessibilityDecrement(): Tells the accessibility element to increment or decrement the value of its content.
    ⚠️ The element must have an accessibilityTrait of adjustable in order for the method to be triggered.
    This can be seen implemented in UISliders
  • accessibilityPerformEscape(): Dismisses a modal view and returns the success or failure of the action.
  • accessibilityActivate(): Tells the element to activate itself and report the success or failure of the operation.
  • accessibilityFrameInContainerSpace: The frame of the accessibility element, in the coordinate space of its container view.
    Use this property to set the frame rectangle of an element whose frame rectangle could be affected by its container view.
    i.e. titleLabel.frame.union(subtitleLabel.frame)
    Use frame because you need coordinates in the screen rather than coordinates related to a parent view. Read more on differences of frames and bounds here.
    ⚠️ Sometimes the a11y frame doesn’t appear correctly, look into setting the accessibilityFrameInContainerSpace in the viewDidLayoutSubviews() method.
  • accessibilityViewIsModal: A Boolean value that indicates whether VoiceOver ignores the accessibility elements within views that are siblings of the element.
    ⚠️ Important: Sometimes when a view controller is not fully presented, VO can detect elements outside of the currently presented view controller. Simply set this property to true, and this will make VO access elements only within the current view controller.

References

https://developer.apple.com/accessibility/ios/
https://developer.apple.com/documentation/objectivec/nsobject/uiaccessibility
https://developer.apple.com/videos/play/wwdc2018/226
https://developer.apple.com/videos/play/wwdc2016/202
https://developer.apple.com/videos/frameworks/accessibility/

Have some extra minutes? Check out this GitHub repo:
Computer-science-with-ios ⭐️

📌 Find me on LinkedIn and GitHub here. 😃

Feel free to leave any accessibility tips and tricks you’ve found in the comment section below!

--

--

Rinni Swift
Geek Culture

iOS engineer at PayPal and I write stories — Join me on my journey. 📍San Francisco, CA