-
Notifications
You must be signed in to change notification settings - Fork 4
Spec: Text ‐ Accessibility
Swift's Text
contents are read out loud by default by VoiceOver. The Text
offers various methods for configuring VoiceOver and providing accessibility information.
If you are unfamiliar with VoiceOver, here is a very brief guide on VoiceOver Basics to make sure you know how to test our example application.
It's recommended to use a real physical device for accessibility testing, but as a fallback option, the Accessibility Inspector is also available (this won't be discussed in this spec).
To turn on VoiceOver, go to Settings > Accessibility > VoiceOver, then toggle the switch for the VoiceOver. Now, your phone is in "VoiceOver mode" and the screen's content will be read out loud.
VoiceOver changes the gestures you use to control your phone, the gestures you are familiar with will no longer work! When VoiceOver is on, you need to use VoiceOver gestures to operate iPhone, so to prevent any headache (e.g. not being able to turn off VoiceOver after your accessibility testing is complete), make sure you familiarize yourself with VoiceOver gestures in the next section before you toggle VoiceOver.
Here, I share the VoiceOver gestures that you'll probably need to use to test our example app's accessibility.
- jump to next and previous items: swipe right and left
- select and speak item: single tap
- activate item, e.g. "click" on a button to jump to the next screen, or open an application: double tap
- access rotor: rotate two fingers (as if you’re turning a dial)
- the rotor will show up, and you can switch between the rotor's options by rotating clockwise or counterclockwise. If you are happy with the selection (e.g. headings for testing the
accessibilityHeading
below), lift up your fingers.
- the rotor will show up, and you can switch between the rotor's options by rotating clockwise or counterclockwise. If you are happy with the selection (e.g. headings for testing the
- jump to next or previous item depending on the rotor settings (e.g. jump to next heading): swipe up and down
- scroll up or down one page: three finger swipe up or down
- go to home: drag one finger up from the bottom edge of the screen until you hear two rising tones
- open app switcher: drag one finger up from the bottom edge of the screen until you hear three rising tones
Please reference the official guide on VoiceOver gestures and the guide on how to operate your phone (unlock, go to home, switch apps) in case you get stuck.
The pitch of the spoken text can be raised and lowered with the speechAdjustedPitch
instance method. The instance method receives a Double
value indicating how much higher or lower to change the pitch.
Values between
-1
and0
result in a lower pitch while values between0
and1
result in a higher pitch. The method clamps values to the range-1
to1
.
Text("Lowered pitch").speechAdjustedPitch(-1.0)
Text("Slightly lowered pitch").speechAdjustedPitch(-0.3)
Text("Normal pitch").speechAdjustedPitch(0)
Text("Slightly raised pitch").speechAdjustedPitch(0.3)
Text("Raised pitch").speechAdjustedPitch(1.0)
The speechAlwaysIncludesPunctuation
"sets whether VoiceOver should always speak all punctuation in the text view".
When enabled, commas, apostrophes, etc. are announced by VoiceOver.
// Apostrophes, commas, semicolon, etc are all announced.
Text("Includes punctuation: All the world's a stage, And all the men and women merely players;").speechAlwaysIncludesPunctuation(true)
// The text is simply spoken without punctuation.
Text("Does not include punctuation: All the world's a stage, And all the men and women merely players;").speechAlwaysIncludesPunctuation(false)
When speechSpellsOutCharacters
is enabled, the text is spoken as individual letters, character by character.
This is important for text that is not meant to be spoken together, like:
- An acronym that isn’t a word, like APPL, spoken as “A-P-P-L”.
- A number representing a series of digits, like 25, spoken as “two-five” rather than “twenty-five”.
Text("APPL").speechSpellsOutCharacters(true)
Text("125").speechSpellsOutCharacters(true)
accessibilityHeading
adds heading level information to the text. The levels go from h1
to h6
, and there is an additional unspecified
level.
Assistive technologies can use this to improve a users navigation through multiple headings.
Users can use the rotor to select "Headings", then they can jump from one heading to the next, this enables users finding the content they are looking for more easily.
Text("Heading h1").accessibilityHeading(.h1).accessibilityAddTraits([.isHeader])
For the headings to be recognized, I also had to add the accessibilityAddTraits
modifier with the .isHeader
value.
Even though I expected, I didn't find a way to jump only between headers of the same level, and VoiceOver simply jumps from one heading to the next regardless of their level.
When VoiceOver is supposed to announce an alternative instead of the Text
's content, you can use the accessibilityLabel
. It accepts simple strings and localized strings, too.
Text("Text with accessibility label").accessibilityLabel("If the text has an accessibility label, only the accessibility label is spoken by VoiceOver, the text itself is skipped.")
Text("Not announced").accessibilityLabel("Announced")
There are, unfortunately, two modifiers that I couldn't understand how they work, or better put, I couldn't create a demo that shows the modifiers in action:
-
speechAnnouncementsQueued
: this should control "whether to queue pending announcements behind existing speech rather than interrupting speech in progress". In all examples I created, the queuing never worked and the text was immediately announced as the text was selected. -
accessibilityTextContentType
: assistive technologies are supposed to "use this property to choose an appropriate way to output the text". Unfortunately, regardless of the accessibility text content type, the tests were always announced the same.