VoiceOver Support
What is VoiceOver?
VoiceOver is Apple screen reader for blind and low-vision users. It reads aloud the content on screen and provides gesture-based navigation.
Accessibility Labels
Every interactive element needs an accessibility label:
// SwiftUI
Image(systemName: "heart.fill")
.accessibilityLabel("Favorite")
Button(action: addToCart) {
Image(systemName: "cart")
}
.accessibilityLabel("Add to cart")
// UIKit
addToCartButton.accessibilityLabel = "Add to cart"
Accessibility Hints
Provide context about what an action does:
Button(action: toggleFavorite) {
Image(systemName: isFavorite ? "heart.fill" : "heart")
}
.accessibilityLabel(isFavorite ? "Remove from favorites" : "Add to favorites")
.accessibilityHint("Double tap to toggle favorite status")
Accessibility Traits
Identify the role of UI elements:
// SwiftUI
Text("Breaking News")
.accessibilityAddTraits(.isHeader)
TextField("Email", text: $email)
.accessibilityAddTraits(.isSearchField)
// UIKit
headlineLabel.accessibilityTraits = .header
searchField.accessibilityTraits = .searchField
VoiceOver Navigation
Test navigation flow:
- Enable VoiceOver in Settings > Accessibility > VoiceOver
- Swipe right to move to next element
- Swipe left to move to previous element
- Double-tap to activate
- Use rotor (two-finger twist) to navigate by heading, link, etc.
Dynamic Type
What is Dynamic Type?
Dynamic Type lets users adjust text size across all apps. Your app should respect their preferred text size.
Supporting Dynamic Type in SwiftUI
// SwiftUI automatically supports Dynamic Type with system fonts
Text("Hello World")
.font(.body)
// Custom fonts should use scaled metrics
Text("Title")
.font(.custom("MyFont", size: 17).scaledMetric(relativeTo: .body))
Supporting Dynamic Type in UIKit
// Use preferred font
headlineLabel.font = UIFont.preferredFont(forTextStyle: .headline)
headlineLabel.adjustsFontForContentSizeCategory = true
// Custom fonts with scaling
let customFont = UIFont(name: "MyFont", size: 17)!
headlineLabel.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: customFont)
Layout Adaptation
Adjust layouts for larger text sizes:
struct AdaptiveLayout: View {
@Environment(\.dynamicTypeSize) var typeSize
var body: some View {
if typeSize >= .accessibility2 {
// Stack vertically for large text
VStack {
imageView
textContent
}
} else {
// Side by side for normal text
HStack {
imageView
textContent
}
}
}
}
Testing Dynamic Type
- Enable in Settings > Accessibility > Display and Text Size > Larger Text
- Use the Xcode Environment preview to test different sizes
- Test with Accessibility sizes enabled
- Ensure no text is clipped or overlapping
Accessibility Audit
Xcode Accessibility Inspector
Use the Accessibility Inspector (Xcode > Open Developer Tool) to:
- View the accessibility hierarchy
- Check labels, hints, and traits
- Identify missing accessibility information
- Test VoiceOver focus order
Automated Audit
Run an accessibility audit from Xcode:
- Select Product > Perform Action > Accessibility Audit
- Choose All Issues or specific categories
- Review warnings and errors
- Fix missing labels, insufficient contrast, etc.
Common Accessibility Issues
- Missing accessibility labels on images and buttons
- Empty accessibility groups
- Insufficient color contrast
- Text that cannot scale with Dynamic Type
- Interactive elements that are too small (minimum 44x44 points)
- Custom controls without accessibility support
Color and Contrast
// Ensure sufficient contrast
Text("Important")
.foregroundStyle(Color(.label)) // Adapts to light/dark mode
// Avoid using color alone to convey information
HStack {
Circle().fill(isOnline ? Color.green : Color.red)
Text(isOnline ? "Online" : "Offline")
}
.accessibilityElement(children: .combine)
Accessibility Testing Checklist
- All images have accessibility labels
- All buttons have descriptive labels
- Dynamic Type is supported
- Color contrast meets WCAG 2.1 AA standards
- No information is conveyed by color alone
- Focus order is logical
- Custom controls expose correct traits
- Tested with VoiceOver enabled
- Tested with large text sizes
- Tested with reduced motion enabled
Quiz
1. What does .accessibilityLabel do in SwiftUI?
2. What is the minimum touch target size recommended by Apple?
3. How do you support Dynamic Type in SwiftUI?
4. What is the purpose of accessibilityHint?
Flashcards
Question
What is VoiceOver?
Click to reveal answer
Answer
Apple built-in screen reader that reads aloud screen content and provides gesture-based navigation for blind and low-vision users.
Question
What is Dynamic Type?
Click to reveal answer
Answer
A system setting that lets users choose their preferred text size. Apps should respect this setting and scale text accordingly.
Question
What is the minimum recommended touch target size?
Click to reveal answer
Answer
44x44 points. This ensures interactive elements are large enough for users with motor impairments to tap accurately.
Revision Notes
Key Takeaways
- 1. Every interactive element needs an accessibility label
- 2. Support Dynamic Type with system fonts or scaledMetric
- 3. Minimum touch target size is 44x44 points
- 4. Use Accessibility Inspector to audit your app
- 5. Test with VoiceOver and large text sizes regularly
Interview Tips
- • Explain how to implement VoiceOver support in SwiftUI
- • Describe how to support Dynamic Type
- • Discuss common accessibility issues and how to fix them
- • Walk through using the Accessibility Inspector
Cheat Sheet
Accessibility Quick Reference
- .accessibilityLabel: VoiceOver description
- .accessibilityHint: Action result description
- .accessibilityAddTraits: element role
- Dynamic Type: use system fonts or scaledMetric
- Minimum touch target: 44x44 points
- Use Accessibility Inspector for auditing
- Never use color alone to convey information