App accessibility for Switch Control
Accessibility 入门 20m

为 Switch Control 优化 App 无障碍体验

App accessibility for Switch Control

2020年6月23日

在 Apple 官方观看视频

一句话判断

如果你从未考虑过 Switch Control 用户如何使用你的 App,这场 Session 是一个低成本入门——你会发现只要做好 VoiceOver 标注,大多数场景下 Switch Control 就自然能工作。

这场 Session 讲了什么

Switch Control 是 iOS 内置的辅助功能,允许运动障碍用户通过一个或多个外部开关(如按键、吹气传感器、头部追踪)来操控设备。它通过扫描界面上的可交互元素,用户在想要的元素上触发开关即可完成操作。

Session 首先讲解了 Switch Control 的两种模式:Item Scan(逐项扫描)和 Point Scan(点扫描)。然后通过实际演示展示了 Switch Control 用户如何在不同类型的 App 中导航。核心信息是:如果你的 App 已经正确实现了 VoiceOver 支持(UIAccessibility 标注),Switch Control 大多数情况下能正常工作。

但也有一些 Switch Control 特有的优化点:减少不必要的可交互元素(避免扫描过多项目)、合理设置 accessibility traits(让系统知道某个元素是按钮还是纯文本)、以及确保自定义手势操作的替代方案。

值得深挖的点

VoiceOver 和 Switch Control 的关系。 两者共享同一套 Accessibility 树。VoiceOver 用户通过滑动选择元素,Switch Control 用户通过扫描选择元素,但它们依赖的底层信息(标签、Traits、Value 等)完全相同。这意味着做好 VoiceOver 支持就等于做好了 Switch Control 的大部分工作。

减少”噪音”元素的重要性。 Switch Control 在扫描时会遍历所有可访问的元素。如果你的界面有大量装饰性元素被错误标记为可交互的,Switch Control 用户需要等待更长的扫描周期。合理使用 isAccessibilityElement = false 隐藏不重要的元素。

代码片段

// 正确设置自定义视图的无障碍属性
class CustomButton: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 标记为可交互的无障碍元素
        isAccessibilityElement = true
        accessibilityLabel = "播放音乐"  // 清晰描述操作
        accessibilityTraits = .button  // 标记为按钮类型
        accessibilityHint = "双击以开始播放"  // 提示操作结果
    }
}
// 隐藏装饰性元素,减少扫描噪音
class DecorativeImageView: UIImageView {
    override init(image: UIImage?) {
        super.init(image: image)
        isAccessibilityElement = false  // 装饰性图片不需要被扫描到
    }
}

// 对分组元素使用无障碍容器
class MediaControlsView: UIView {
    override func accessibilityElementCount() -> Int {
        return 3  // 只暴露三个关键控件:上一曲、播放、下一曲
    }
}
// 为复杂自定义控件提供完整的无障碍信息
class CustomSlider: UIControl {
    var value: Float = 0.5
    
    func updateAccessibility() {
        isAccessibilityElement = true
        accessibilityLabel = "音量"
        accessibilityValue = "\(Int(value * 100))%"
        accessibilityTraits = [.adjustable, .button]
    }
    
    // 支持 Switch Control 的增减操作
    override func accessibilityIncrement() {
        value = min(value + 0.1, 1.0)
        updateAccessibility()
        sendActions(for: .valueChanged)
    }
    
    override func accessibilityDecrement() {
        value = max(value - 0.1, 0.0)
        updateAccessibility()
        sendActions(for: .valueChanged)
    }
}

最佳实践

  • 先做好 VoiceOver 再考虑 Switch Control。 两者的底层标注是共享的,VoiceOver 做好了,Switch Control 通常也能正常使用。
  • 减少不必要的可交互元素。 装饰性图片、间距占位符等应设为 isAccessibilityElement = false,让扫描更高效。
  • 为自定义控件实现 accessibilityIncrement/Decrement。 对于滑块、选择器等连续值控件,这两个方法让用户可以通过开关逐步调整。
  • 测试时启用 Switch Control 真实体验。 在设置 > 辅助功能 > Switch Control 中开启,用屏幕开关模拟真实用户操作流程。

还有什么值得关注

  • Switch Control 支持外部蓝牙开关设备,测试时可以使用屏幕上的开关模拟
  • Group Items 功能可以将多个元素合并为一个扫描单元,减少扫描步骤
  • 自定义手势操作需要提供基于开关的替代方案
  • App 的无障碍支持也影响 Siri Suggestions 和预测输入的准确性
WWDC 2020