Slide 1

Slide 1 text

Accessibility on Apple Platforms: Beyond VoiceOver Bas Broek @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 1

Slide 2

Slide 2 text

Bas Broek • iOS, Accessibility & more @ WeTransfer • Previously macOS Accessibility / VoiceOver @ Apple • Swift for Good co-author @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 2

Slide 3

Slide 3 text

Introductions @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 3

Slide 4

Slide 4 text

It's the right thing to do. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 4

Slide 5

Slide 5 text

If only it were that easy. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 5

Slide 6

Slide 6 text

⚠ Hands-on @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 6

Slide 7

Slide 7 text

My goal: Leave with improved accessibility in your app that you can demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 7

Slide 8

Slide 8 text

Please interrupt me if you have any questions @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 8

Slide 9

Slide 9 text

... and/or if you want to demo something! @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 9

Slide 10

Slide 10 text

A note on "ticket- creating" mode @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 10

Slide 11

Slide 11 text

"Evolution" of Accessibility on Apple platforms • VoiceOver, Switch Control • Voice Control • Full Keyboard Access • ... and more; think zoom, Dynamic Type, Reduce Motion etc. • ... as well as Dark Mode, Back Tap, Siri, haptics @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 11

Slide 12

Slide 12 text

Two layers of accessibility @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 12

Slide 13

Slide 13 text

VoiceOver @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 13

Slide 14

Slide 14 text

UIKit accessibilityLabel accessibilityTraits accessibilityValue accessibilityHint @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 14

Slide 15

Slide 15 text

UIKit accessibilityLabel - "Volume" accessibilityTraits - .adjustable accessibilityValue - "56%" accessibilityHint - "Swipe up or down to adjust." @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 15

Slide 16

Slide 16 text

SwiftUI .accessibilityLabel("Volume") .accessibilityAdjustableAction { direction in } .accessibilityValue("50%") .accessibilityHint("Swipe up or down to adjust.") @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 16

Slide 17

Slide 17 text

Let's verify @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 17

Slide 18

Slide 18 text

Custom Content @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 18

Slide 19

Slide 19 text

import Accessibility class MyObjectContainingTweetCell: AXCustomContentProvider { var _accessibilityCustomContent: [AXCustomContent] = [] var accessibilityCustomContent: [AXCustomContent]! { get { _accessibilityCustomContent } set { _accessibilityCustomContent = newValue } } func setupTweetCell(with tweet: Tweet) { accessibilityCustomContent = [ .init( label: NSLocalizedString("Replies", comment: ""), value: String(describing: tweet.replies.count) ) ] } } @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 19

Slide 20

Slide 20 text

.accessibilityCustomContent( "Replies", String(describing: tweet.replies.count) ) @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 20

Slide 21

Slide 21 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 21

Slide 22

Slide 22 text

Performing Escapes @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 22

Slide 23

Slide 23 text

override func accessibilityPerformEscape() { dismiss() return true } .accessibilityAction(.escape) {} @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 23

Slide 24

Slide 24 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 24

Slide 25

Slide 25 text

Magic tap @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 25

Slide 26

Slide 26 text

/// Performs a salient action. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 26

Slide 27

Slide 27 text

override func accessibilityPerformMagicTap() { transferFile() return true } .accessibilityAction(.magicTap) {} @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 27

Slide 28

Slide 28 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 28

Slide 29

Slide 29 text

Image exploration @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 29

Slide 30

Slide 30 text

.accessibilityTraits.insert(.image) .accessibilityAddTraits(.isImage) @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 30

Slide 31

Slide 31 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 31

Slide 32

Slide 32 text

Voice Control @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 32

Slide 33

Slide 33 text

accessibilityUserInputLabels @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 33

Slide 34

Slide 34 text

! @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 34

Slide 35

Slide 35 text

/// The default value for this property is an empty array /// unless the element is a UIKit control. /// In that case, the value is an array with /// an appropriate label, if different from `accessibilityLabel`. /// /// Use this property when the `accessibilityLabel` isn't appropriate for /// dictated or typed input. /// For example, an element that contains additional descriptive /// information in its `accessibilityLabel` can return a more concise label. /// /// The primary label is first in the array, optionally followed /// by alternative labels in descending order of importance. /// /// If this property returns an empty array or an invalid value, /// the system uses `accessibilityLabel` instead. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 35

Slide 36

Slide 36 text

/// The default value for this property is an empty array /// unless the element is a UIKit control. /// In that case, the value is an array with /// an appropriate label, if different from `accessibilityLabel`. /// /// Use this property when the `accessibilityLabel` isn't appropriate for /// dictated or typed input. /// For example, an element that contains additional descriptive /// information in its `accessibilityLabel` can return a more concise label. /// /// The primary label is first in the array, optionally followed /// by alternative labels in descending order of importance. /// /// If this property returns an empty array or an invalid value, /// the system uses `accessibilityLabel` instead. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 36

Slide 37

Slide 37 text

"TAP TO COPY LINK" "Tap 'tap to copy link'" @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 37

Slide 38

Slide 38 text

"TAP TO COPY LINK" "Tap 'tap to copy link'" "Tap 'copy link'" @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 38

Slide 39

Slide 39 text

"It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph" "Tap 'It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph'" @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 39

Slide 40

Slide 40 text

"It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph" "Tap 'It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph'" "Tap 'article, 1'" @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 40

Slide 41

Slide 41 text

UIKit copyLinkButton.accessibilityLabel = "Tap to copy link" copyLinkButton.accessibilityUserInputLabels = [ "Copy link", "Copy" ] article.accessibilityLabel = "It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph" article.accessibilityUserInputLabels = [ "Article", "News", article.accessibilityLabel ] @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 41

Slide 42

Slide 42 text

SwiftUI .accessibilityLabel( "Tap to copy link" ) .accessibilityInputLabels([ "Copy link", "Copy" ]) .accessibilityLabel( "It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph" ) .accessibilityInputLabels([ "Article", "News", "It's Complicated: Inside an A. Lange & Söhne Split-Seconds Chronograph" ]) @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 42

Slide 43

Slide 43 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 43

Slide 44

Slide 44 text

Full Keyboard Access @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 44

Slide 45

Slide 45 text

/// The default value for this property is an empty array /// unless the element is a UIKit control. /// In that case, the value is an array with /// an appropriate label, if different from `accessibilityLabel`. /// /// Use this property when the `accessibilityLabel` isn't appropriate for /// dictated or typed input. /// For example, an element that contains additional descriptive /// information in its `accessibilityLabel` can return a more concise label. /// /// The primary label is first in the array, optionally followed /// by alternative labels in descending order of importance. /// /// If this property returns an empty array or an invalid value, /// the system uses `accessibilityLabel` instead. @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 45

Slide 46

Slide 46 text

! @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 46

Slide 47

Slide 47 text

Demo @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 47

Slide 48

Slide 48 text

A lot of demos Consider using assistive technologies for your product demos! @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 48

Slide 49

Slide 49 text

Championing accessibility 1-1 sessions (may) help @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 49

Slide 50

Slide 50 text

Loopin' back • VoiceOver support gets you most of the way there • Adding Voice Control support will get you ±all the way • ... to also support Full Keyboard Access on iOS! @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 50

Slide 51

Slide 51 text

One last thing... @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 51

Slide 52

Slide 52 text

WeTransfer: Mission Accessible @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 52

Slide 53

Slide 53 text

Thank you! @basthomas @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 53

Slide 54

Slide 54 text

References • https://www.basbroek.nl/getting-started-voiceover • https://www.basbroek.nl/custom-tab-bar-accessibility • https://developer.apple.com/videos/play/ wwdc2021/10120/ • https://about.wetransfer.com/accessibility @basthomas, June 23, 2022 @ Appdevcon, Amsterdam, the Netherlands 54