移动/游戏
为 iOS/macOS 应用构建和审计无障碍支持(Voice…
在实现或审计 SwiftUI、UIKit、AppKit 界面的无障碍功能时,确保辅助技术用户能完成所有常见任务。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
为 iOS/macOS 应用构建和审计无通用
解决思路
- 优先使用语义化系统控件;自定义控件必须暴露与系统控件相同的名称、角色、值、状态和操作。
- 确保每个任务都能通过辅助输入完成:不要让手势、颜色、运动、悬停状态或视觉布局成为获取含义或执行操作的唯一途径。
- 在导航、呈现、更新和关闭过程中保持焦点和遍历顺序有意图。
- 让文本、布局、对比度、透明度和运动适应用户的无障碍设置。
- 将 App Store 无障碍声明视为有证据支持的产品声明,而不是孤立控件级支持的汇总。
- 按 VoiceOver 固定顺序设计标签、值、特征和提示:标签 -> 值 -> 特征 -> 提示。
- 使用 @AccessibilityFocusState(iOS 15+)管理无障碍焦点:用 Bool 表示单目标焦点,用可选 Hashable 枚举表示多目标焦点。
- 在 sheet、alert 或 popover 关闭后,将 VoiceOver 焦点返回到触发它的元素;必要时加约 100ms 延迟等待过渡完成。
- 自定义模态覆盖层需添加 .isModal 特征和 .escape 操作以捕获焦点并支持关闭。
- 在 UIKit 中用 UIAccessibility.post 发送通知:.announcement 宣布状态变化,.layoutChanged 移动焦点到特定元素,.screenChanged 移动焦点到新屏幕。
- 使用系统文本样式缩放文本;用 @ScaledMetric(relativeTo:) 缩放图标尺寸、间距、控件高度和自定义点击区域等非文本尺寸。
- 为内容密集的屏幕添加自定义转子(custom rotors),让 VoiceOver 用户快速导航到特定内容类型。
- 尊重系统无障碍环境值:accessibilityReduceMotion、accessibilityReduceTransparency、colorSchemeContrast、legibilityWeight。
- 在 Reduce Motion 下,将滑动、弹跳、视差、弹簧和大空间过渡替换为透明度变化、即时状态变化或无动画;审查所有移动过渡,包括行删除、数量变化、sheet 或结账呈现和模态关闭。
- 在 Reduce Transparency 下使用实色背景;在 Increase Contrast 下使用更强颜色;在 Bold Text 下使用粗体字重。
- 装饰性图片用 Image(decorative:) 或 .accessibilityHidden(true) 隐藏;仅当图片不提供相邻可访问文本之外的信息时才视为装饰性。
- 图标加文本时用 Label 自动处理;仅图标按钮必须有 accessibilityLabel。
- 每个交互元素必须有可朗读的无障碍标签(不能只有 emoji 或符号),且标签在可见屏幕内唯一。
- 将 accessibilityInputLabels 视为冻结前的无障碍工作,用于长、别扭、本地化、含缩写或常被简化的朗读标签;按重要性降序列出替代标签。
- 对任何主要标签难以朗读的可见目标广泛应用 accessibilityInputLabels,包括重复行操作、数量控件、账户/设置链接、媒体控件和含缩写或产品名的本地化标签。
- 用 Voice Control 测试:说 "Show Names" 和 "Show Numbers" 验证所有交互元素可定位;Show Names 确认可朗读标签,Show Numbers 确认名称缺失、重复或别扭时每个可见交互目标仍可到达。
- 用 .accessibilityElement(children: .combine) 分组相关内容以减少 Switch Control 扫描停靠点;每个扫描目标应有意义且可操作。
- Switch Control 用户无法执行滑动删除、长按或多指手势;用 .accessibilityAction(named:) 自定义操作暴露这些交互,Switch Control 会以菜单呈现。
- 自定义控件若点击区域非标准,确保 accessibilityFrame 准确反映可点击区域(用于点扫描模式)。
- 审计全键盘访问:每个交互元素可用键盘到达并激活,遍历顺序逻辑且不困住焦点,焦点指示器在所有对比度和文字大小设置下可见,仅手势行为有键盘可操作替代,应用快捷键不覆盖 Cmd+C、Cmd+V、Cmd+Tab 等系统快捷键。
- 确保元素顺序和分组在 VoiceOver 滑动顺序、Switch Control 扫描、Voice Control 覆盖层和全键盘访问审查中遵循视觉和任务顺序;检查缺失或重复标签、过多行子元素、隐藏自定义控件、焦点陷阱和与任务顺序不一致的分组。
- 支持 Assistive Access(iOS 18+):用 @Environment(\.accessibilityAssistiveAccessEnabled) 检测并显示简化界面;减少视觉复杂度、使用清晰字面语言、最小化同时呈现的选择数量。
- UIKit 自定义视图需暴露有意义的元素、标签、值、特征和操作;用 insert/remove 修改特征;使自定义覆盖层模态化;使用适当的 announcement、layoutChanged 或 screenChanged 通知。
- AppKit 优先使用标准控件;自定义 NSView 或虚拟元素需暴露正确的 NSAccessibility 角色、标签、值、操作和状态变化通知。
- 用 .accessibilityCustomContent 提供有用的次要信息而不增加滑动停靠点;仅对应自动朗读的内容保留高重要性。
- App Store 无障碍营养标签:在推荐声明前,要求有证据表明用户能在相关设备类型上用该功能完成所有常见任务;使用结构化的常见任务×无障碍功能矩阵;在相关时包含纯音频内容的字幕;明确警告 App Store 无障碍答案必须保持准确,不得视为营销声明。
- 手动测试:用 Accessibility Inspector 审计标签、特征和对比度;在设置中启用 VoiceOver、Voice Control、全键盘访问、Switch Control 和动态字体逐一测试每个屏幕。
- 用 XCTest 自动化测试:用稳定的 accessibility identifiers 定位 XCUIElement,断言存在性、启用/选中状态、有意义的标签/值以及测试环境暴露的 hasFocus;覆盖关闭焦点恢复、每个模态退出路径和手势替代方案。
- UI 自动化补充而非替代 VoiceOver、Voice Control、Switch Control、键盘、动态字体、对比度、Reduce Motion 和 Reduce Transparency 的手动测试。
- 避免常见错误:特征赋值覆盖行为(应 insert/remove 或使用 SwiftUI 特征修饰符);关闭丢失焦点(应返回焦点到触发器);行产生过多滑动停靠点(应有意图分组);标签重复控件类型或遗漏图标含义(应使用简洁可朗读的操作/名称,特征会宣布类型);运动、文字大小、对比度或透明度固定(应响应匹配的无障碍偏好和自适应文本样式);目标小或仅靠颜色(应提供 44×44 目标加文本、形状或图标语义);自定义覆盖层非模态(应暴露模态语义、escape 操作和恢复)。
- 按审查清单记录每个常见任务的证据:语义(名称、角色/状态/值、装饰/仅颜色/仅手势/可调整内容的替代方案);导航(分组和遍历有意图、模态暴露模态和 escape 行为、焦点返回发起控件);输入(Voice Control 名称可朗读且唯一、Show Names/Numbers 均可用、Switch Control 暴露手势替代、全键盘访问无不可达控件/陷阱/覆盖系统快捷键);适应(动态字体、Reduce Motion、Reduce Transparency、Increase Contrast、Bold Text 和 44×44 点在代表性布局和状态中验证);自动化(XCTest 覆盖稳定标识符、状态、可用焦点和每个模态退出路径,不替代手动辅助技术测试);并发(跨隔离边界的无障碍值和通知负载为 Sendable);声明(每个 App Store 无障碍声明由完成的常见任务证据矩阵支持,覆盖每个声明设备类型)。
适用边界 · 注意事项
- 需要实现键盘焦点机制(Tab/方向焦点、.focusable()、@FocusState、focusSection()、场景焦点值、tvOS 焦点、UIFocusGuide)时,应使用 focus-engine 技能,而非本技能。
- 没有证据支持常见任务完成时,不要推荐 App Store 无障碍营养标签声明。
- 不要将 UI 自动化测试作为 VoiceOver、Voice Control、Switch Control、键盘、动态字体、对比度、Reduce Motion 和 Reduce Transparency 手动测试的替代品。