WWDC Quick Look 💓 By SwiftGGTeam
App accessibility for Switch Control

App accessibility for Switch Control

观看原视频

Highlight

Switch Control 是 iOS 内置的辅助功能,允许运动能力受限的用户用外部开关控制屏幕光标;本 session 展示了如何用 accessibilityNavigationStyleaccessibilityElements、焦点回调和 UIAccessibilityCustomAction 减少扫描等待、自动展示卡片内容,并把双击/长按操作放进顶层菜单。


核心内容

Switch Control 用户常常通过轮椅上的开关、头部点击、舌头点击或吸管呼吸来操作设备。系统会让光标在界面元素之间移动,用户等到目标元素被选中后再触发开关。对于触摸用户来说一次点击就完成的事,对开关用户可能意味着等待、进组、打开菜单,再选择动作。(00:59

这场 session 把问题放进一个叫 Shape Shuffle 的儿童学习游戏。游戏里有弯曲的关卡路径、需要翻开的卡片,以及频繁使用的双击和长按。触摸用户玩起来很自然,Switch Control 用户会遇到三个障碍:关卡扫描顺序不对,找远处关卡要等很久;每张卡片都要额外操作才看得到内容;双击和长按要反复进入 gestures 子菜单。(05:15

Apple 给出的思路很直接:先把 App 做到完整支持 VoiceOver,因为许多 accessibility 标注会被 Switch Control 复用;随后针对开关用户补上几处体验 polish。关卡列表用分组和显式顺序减少等待,卡片用焦点回调自动翻开,常用手势用 Custom Actions 放到顶层菜单。(04:22

收尾部分提醒开发者把运动障碍用户的操作成本纳入产品流程。删除账号、删除全部数据这类高后果操作要确认;验证码和配对码界面在 Switch Control 运行时不应设置短超时;包含账号、医疗等隐私内容的界面要减少长时间暴露。(12:29


详细内容

控制扫描分组和顺序

07:49)Shape Shuffle 的关卡沿着弯曲路径排列,但 Switch Control 默认按从上到下、从左到右扫描。开发者可以先把一组关卡合并成一个扫描组,再显式指定组内元素顺序。

containerView.accessibilityNavigationStyle = .combined

containerView.accessibilityElements = [levelFourView, levelFiveView, levelSixView]

关键点:

  • accessibilityNavigationStyle = .combined 让容器内的元素作为一个组合参与扫描,减少顶层元素数量。
  • accessibilityElements 覆盖默认几何排序,适合弯曲路径、棋盘、地图和其他视觉顺序不等于阅读顺序的界面。
  • 这个改动直接解决 level 30 这类远处目标的等待问题,因为用户先进入正确的组,再在组内按设计顺序移动。

让焦点自动展示内容

08:47)卡片游戏依赖点击来翻面。手动扫描的 Switch Control 用户每移动到一张卡都要额外触发操作,成本会随着卡片数量增长。session 的做法是在卡片获得辅助功能焦点时翻到正面,失去焦点时翻回背面。

class CardView: UIView {
    var orientation: CardOrientation

    enum CardOrientation {
        case front
        case back
    }

    override func accessibilityElementDidBecomeFocused() {
        self.flip(to: .front)
    }

    override func accessibilityElementDidLoseFocus() {
        self.flip(to: .back)
    }

    // 其余 class 内容...
}

关键点:

  • accessibilityElementDidBecomeFocused() 在辅助功能焦点到达卡片时调用。
  • self.flip(to: .front) 把原本需要点击才能看到的内容提前展示出来。
  • accessibilityElementDidLoseFocus() 让卡片离开焦点后恢复背面,保持游戏规则。
  • 这个行为可以做成用户设置,因为 transcript 提到自动扫描用户未必需要它,手动扫描用户更受益。

把常用手势放进顶层菜单

09:15)游戏中的双击用于添加卡片,长按用于 pin 卡片。Switch Control 用户能执行这些手势,但要频繁进入 gestures 子菜单。UIAccessibilityCustomAction 把这些常用操作变成顶层菜单项,减少菜单层级。

func configureActions() {
    let pinAction = UIAccessibilityCustomAction(
        name: "Pin Card") { (_) -> Bool in
            self.setPinned(true)
            return true
        }
    pinAction.image = UIImage(systemName: "pin")

    let addAction = UIAccessibilityCustomAction(
        name: "Add Card") { (_) -> Bool in
            self.setSelected(true)
            return true
        }
    addAction.image = UIImage(systemName: "add.square")

    self.accessibilityCustomActions = [addAction, pinAction]
}

关键点:

  • 每个 UIAccessibilityCustomAction 对应一个用户可触发的行为。
  • closure 返回 true 表示动作已处理。
  • accessibilityCustomActions 决定当前视图在 Switch Control 菜单里暴露哪些操作。
  • iOS 14 允许给 custom action 设置 image;session 使用 SF Symbols 做 pin 和 add 图标,未设置图片时菜单显示动作名称首字母。

检测 Switch Control 与静态文本交互

11:41)session 还点名了两个小 API。一个用于判断 Switch Control 是否正在运行,另一个用于把看起来像静态文本、实际会响应点击的元素纳入 Switch Control 导航。

static var isSwitchControlRunning: Bool { get }

var accessibilityRespondsToUserInteraction: Bool { get set }

关键点:

  • isSwitchControlRunning 适合控制只面向 Switch Control 的体验开关,例如延长验证码页面的超时时间。
  • transcript 同时提到有对应 notification,适合在状态变化时更新界面。
  • accessibilityRespondsToUserInteraction 适合会响应点击的 UILabel 一类静态外观元素。
  • 设置后,Switch Control 会把这类元素当作可导航目标处理,避免用户找不到隐藏交互。

为误触和慢输入留余地

12:44)运动障碍用户可能有 tremors 或其他非自主动作,误触概率更高。高后果操作要加确认;认证码、配对码页面在 Switch Control 运行时要避免短超时;包含账号、医疗等私密信息的界面要尽快收起敏感内容。

关键点:

  • 删除全部数据、退出登录、删除账号等操作要有确认流程。
  • 输入更慢和纠错更慢是 autoscanning 的直接结果,安全流程不能只按触摸用户速度设计。
  • 设备可能固定在轮椅上,屏幕隐私条件弱于手持设备。

核心启发

开关友好的卡片学习模式

做什么:给记忆卡、语言学习或儿童认知游戏增加 Switch Control 模式,焦点到达卡片时自动揭示内容。

为什么值得做:session 的卡片示例表明,反复点击翻卡会让手动扫描用户疲劳。

怎么开始:在卡片 UIView 上实现 accessibilityElementDidBecomeFocused()accessibilityElementDidLoseFocus(),把翻面逻辑放进焦点生命周期,再提供一个设置项让用户打开自动翻卡。

分组扫描的关卡、棋盘和地图

做什么:为关卡地图、座位图、棋盘或楼层图建立符合任务顺序的扫描分组。

为什么值得做:默认从上到下、从左到右的顺序会破坏弯曲路径和空间布局,用户要等更久才能到达目标。

怎么开始:用容器视图承载一组元素,设置 accessibilityNavigationStyle = .combined,再把 accessibilityElements 排成用户完成任务时真正需要的顺序。

顶层菜单里的高频动作

做什么:把 pin、完成、收藏、加入答案这类高频动作放进 Switch Control 顶层菜单。

为什么值得做:双击、长按和 swipe action 虽然可达,但反复进入 gestures 子菜单会拖慢流程。

怎么开始:为每个行为创建 UIAccessibilityCustomAction,在 closure 里调用现有业务方法,最后赋给当前元素的 accessibilityCustomActions

无短超时的验证码流程

做什么:让登录、配对和验证码页面在 Switch Control 运行时使用更宽松的时间窗口。

为什么值得做:autoscanning 用户输入更慢,修正错误也更慢,短超时会把辅助功能用户挡在流程外。

怎么开始:读取 isSwitchControlRunning,在该状态下延长倒计时、暂停自动关闭,或提供重新发送前的明确确认。

可交互标签的无障碍暴露

做什么:把外观像文本、实际能点击的统计项、状态标签或小型控制项纳入 Switch Control 导航。

为什么值得做:Switch Control 需要知道它们会响应用户交互,否则用户可能扫不到关键入口。

怎么开始:对这类元素设置 accessibilityRespondsToUserInteraction = true,再补齐 label、traits 和触发后的状态反馈。


关联 Session

评论

GitHub Issues · utterances