Mac Catalyst 的无障碍设计
Accessibility design for Mac Catalyst
2020年6月25日
一句话判断
Mac Catalyst App 的无障碍支持不是”自动就能工作”的——macOS 有自己的 VoiceOver 行为、键盘导航模式和高对比度需求,你需要专门为 Mac 环境做无障碍适配。
这场 Session 讲了什么
Mac Catalyst 让 iOS App 可以在 macOS 上运行,但在无障碍方面有一些特殊的注意事项。Session 详细讲解了 iOS 和 macOS 在无障碍上的差异。
主要差异包括:macOS 的 VoiceOver 使用不同的手势模型(键盘为主而非触摸);macOS 期望所有可交互元素都支持键盘操作(Tab 导航和 Enter 激活);macOS 的高对比度模式与 iOS 的实现不同;拖拽操作在 Mac 上需要支持鼠标。Session 还介绍了如何使用 Accessibility Inspector 来测试 Mac Catalyst App 的无障碍支持,以及如何在 iOS 和 macOS 之间共享无障碍配置。
值得深挖的点
键盘导航是 Mac 的基本要求
在 iOS 上,VoiceOver 用户通过触摸屏幕来导航。在 macOS 上,用户通过 Tab 键和方向键来导航。你的 Mac Catalyst App 必须支持完整的键盘操作路径。这意味着每个可交互元素都需要设置 isAccessibilityElement = true 和正确的 accessibilityTraits。系统会自动将 UIKit 的焦点系统映射为 macOS 的键盘焦点,但自定义视图需要额外的工作。
macOS 的 VoiceOver 差异
macOS 的 VoiceOver 有一些 iOS 没有的行为。比如 VO 键(Control + Option)组合是 macOS VoiceOver 的修饰键。VO + 空格相当于 iOS 的双击。VO + 左右箭头在元素之间导航。这些映射大部分是自动的,但如果你使用了自定义手势识别器,需要确保它们在 Mac 上有对应的键盘操作。
代码片段
为 Mac Catalyst 配置键盘导航
场景:确保所有按钮和交互元素支持 Tab 导航。
import UIKit
#if targetEnvironment(macCatalyst)
class MacAccessibleView: UIView {
private var submitButton: UIButton!
private var cancelButton: UIButton!
private var textField: UITextField!
func setupAccessibility() {
// 确保所有交互元素都是可访问的
submitButton.isAccessibilityElement = true
submitButton.accessibilityLabel = "提交"
submitButton.accessibilityTraits = .button
cancelButton.isAccessibilityElement = true
cancelButton.accessibilityLabel = "取消"
cancelButton.accessibilityTraits = .button
textField.isAccessibilityElement = true
textField.accessibilityLabel = "输入内容"
textField.accessibilityTraits = .keyboardKey // 表示接受文本输入
}
// 设置 Tab 导航顺序
override var accessibilityElements: [Any]? {
get {
// 定义 Tab 键的导航顺序
return [textField, submitButton, cancelButton]
}
set {
super.accessibilityElements = newValue
}
}
}
#endif
处理 Mac Catalyst 的拖拽无障碍
场景:让拖拽操作支持 VoiceOver 的”拖拽”手势。
class DraggableItemView: UIView {
override var isAccessibilityElement: Bool {
get { return true }
set { super.isAccessibilityElement = newValue }
}
override var accessibilityTraits: UIAccessibilityTraits {
get { return [.button, .allowsDirectInteraction] }
set { super.accessibilityTraits = newValue }
}
override var accessibilityLabel: String? {
get { return "可拖拽项目:\(itemTitle)" }
set { super.accessibilityLabel = newValue }
}
// 提供 VoiceOver 的自定义操作
override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
get {
return [
UIAccessibilityCustomAction(name: "拖拽到收藏") { _ in
self.dragToFavorites()
return true
},
UIAccessibilityCustomAction(name: "拖拽到回收站") { _ in
self.dragToTrash()
return true
}
]
}
set { super.accessibilityCustomActions = newValue }
}
private var itemTitle: String = "默认项目"
private func dragToFavorites() { /* 拖拽到收藏夹 */ }
private func dragToTrash() { /* 拖拽到回收站 */ }
}
适配高对比度模式
场景:在 Mac Catalyst 中检测和适配高对比度模式。
class HighContrastAwareView: UIView {
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
// 检测高对比度模式变化
if traitCollection.accessibilityContrast != previousTraitCollection?.accessibilityContrast {
updateAppearanceForContrast()
}
}
private func updateAppearanceForContrast() {
switch traitCollection.accessibilityContrast {
case .high:
// 高对比度模式:使用更粗的边框和更深的颜色
layer.borderWidth = 2
layer.borderColor = UIColor.labelColor.cgColor
// 确保文字和背景之间有足够的对比度
backgroundColor = .systemBackground
case .normal, .unspecified:
// 正常模式
layer.borderWidth = 0.5
layer.borderColor = UIColor.separator.cgColor
backgroundColor = .secondarySystemBackground
@unknown default:
break
}
}
}
跨平台共享无障碍配置
场景:使用条件编译在 iOS 和 macOS 之间共享代码。
extension UIView {
func configureAccessibility(label: String,
hint: String? = nil,
traits: UIAccessibilityTraits = .button) {
isAccessibilityElement = true
accessibilityLabel = label
accessibilityHint = hint
accessibilityTraits = traits
#if targetEnvironment(macCatalyst)
// Mac 特有的无障碍配置
// 确保支持键盘焦点
if traits.contains(.button) {
// Mac 上按钮需要明确支持焦点
canBecomeFocused = true
}
#endif
}
}
// 使用示例
class MyButton: UIButton {
override func didMoveToSuperview() {
super.didMoveToSuperview()
configureAccessibility(
label: "保存文档",
hint: "双击保存当前文档",
traits: .button
)
}
}
最佳实践
已有项目:如果你有 Mac Catalyst App,用 Mac 的 VoiceOver 测试一遍核心流程。打开 VoiceOver(Command + F5),用 Tab 键和 VO 键导航你的 App。常见问题包括:Tab 键跳过了某些按钮、自定义视图没有焦点环、拖拽操作无法用键盘完成。
新项目:从设计阶段就考虑 Mac 的无障碍需求。确保所有交互元素都有 accessibilityLabel,Tab 导航顺序合理,自定义操作有对应的键盘快捷键。在 CI 中加入 Accessibility Inspector 的自动化检查。
还有什么值得关注
- Mac 的 Accessibility Inspector 比 iOS 版本更强大,可以检查焦点链、模拟键盘导航、检测对比度问题。
- macOS 的”缩放”辅助功能会放大鼠标周围的区域,确保你的 UI 在缩放下仍然可读。
UIAccessibility.isVoiceOverRunning可以在运行时检测 VoiceOver 状态,用于优化性能。