随着技术的进步和移动应用程序在日常生活中的重要性日益增加,创建无障碍应用程序的必要性也日益重要。
React Native 有限的 Accessibility API 一直是开发人员的巨大痛点,因此我们对 Accessibility API 进行了一些更新,以使其更容易创建包容性的移动应用程序。
现有 API 的问题
问题一:两个完全不同但相似的属性 - accessibilityComponentType (Android) 和 accessibilityTraits (iOS)
accessibilityComponentType
和 accessibilityTraits
是两个属性,用于告诉 Android 上的 TalkBack 和 iOS 上的 VoiceOver 用户正在与哪种 UI 元素进行交互。这两个属性最大的问题是
- 它们是两个不同的属性,用法也不同,但目的相同。 在之前的 API 中,它们是两个独立的属性(每个平台一个),这不仅不方便,而且对许多开发人员来说也很困惑。iOS 上的
accessibilityTraits
允许 17 个不同的值,而 Android 上的 accessibilityComponentType
仅允许 4 个值。此外,这些值在很大程度上没有重叠。甚至这两个属性的输入类型也不同。accessibilityTraits
允许传入 traits 数组或单个 trait,而 accessibilityComponentType
仅允许单个值。
- Android 上的功能非常有限。 使用旧属性,Talkback 能够识别的唯一 UI 元素是“button”、“radiobutton_checked”和“radiobutton_unchecked”。
问题二:不存在 Accessibility Hints:
Accessibility Hints 帮助使用 TalkBack 或 VoiceOver 的用户了解当他们在 accessibility 元素上执行操作时会发生什么,而这些操作仅凭 accessibility label 是不明显的。这些提示可以在设置面板中打开和关闭。以前,React Native 的 API 完全不支持 accessibility hints。
问题三:忽略反转颜色:
一些有视力障碍的用户在其手机上使用反转颜色以获得更高的屏幕对比度。Apple 为 iOS 提供了一个 API,允许开发人员忽略某些视图。这样,当用户开启反转颜色设置时,图像和视频就不会失真。React Native 目前不支持此 API。
新 API 的设计
解决方案一:合并 accessibilityComponentType (Android) 和 accessibilityTraits (iOS)
为了解决 accessibilityComponentType
和 accessibilityTraits
之间的混淆,我们决定将它们合并为一个属性。这是有道理的,因为它们在技术上具有相同的预期功能,并且通过合并它们,开发人员在构建 accessibility 功能时不再需要担心平台特定的复杂性。
背景
在 iOS 上,UIAccessibilityTraits
是一个可以设置在任何 NSObject 上的属性。通过 javascript 属性传递到原生的 17 个 traits 中的每一个都映射到 Objective-C 中的 UIAccessibilityTraits
元素。Traits 各自用一个 long int 表示,并且每个设置的 trait 都通过 OR 运算组合在一起。
然而,在 Android 上,AccessibilityComponentType
是 React Native 创造的一个概念,并不直接映射到 Android 中的任何属性。Accessibility 由 accessibility delegate 处理。每个视图都有一个默认的 accessibility delegate。如果你想自定义任何 accessibility 操作,你必须创建一个新的 accessibility delegate,覆盖你想自定义的特定方法,然后将你要处理的视图的 accessibility delegate 设置为与新的 delegate 关联。当开发人员设置 AccessibilityComponentType
时,原生代码会基于传入的组件创建一个新的 delegate,并将视图设置为具有该 accessibility delegate。
所做的更改
对于我们的新属性,我们希望创建这两个属性的超集。我们决定将新属性主要模仿现有属性 accessibilityTraits
进行建模,因为 accessibilityTraits
具有明显更多的值。Android 上这些 traits 的功能将通过修改 Accessibility Delegate 来进行 polyfill。
accessibilityTraits
在 iOS 上可以设置为 17 个 UIAccessibilityTraits 值。但是,我们并没有将所有这些值都包含为新属性的可能值。这是因为设置其中一些 traits 的效果实际上不是很为人所知,并且这些值中的许多值实际上从未使用过。
UIAccessibilityTraits 的值通常用于两种目的之一。它们要么描述 UI 元素具有的角色,要么描述 UI 元素所处的状态。我们观察到之前属性的大多数用途通常使用一个代表角色的值,并将其与“state selected”、“state disabled”或两者结合使用。因此,我们决定创建两个新的 accessibility 属性:accessibilityRole
和 accessibilityState
。
accessibilityRole
新属性 accessibilityRole
用于告诉 Talkback 或 Voiceover UI 元素的角色。这个新属性可以采用以下值之一
none
button
link
search
image
keyboardkey
text
adjustable
header
summary
imagebutton
此属性仅允许传入一个值,因为 UI 元素通常在逻辑上不会承担多个角色。例外情况是 image 和 button,因此我们添加了一个角色 imagebutton,它是两者的组合。
accessibilityStates
新属性 accessibilityStates
用于告诉 Talkback 或 Voiceover UI 元素所处的状态。此属性采用包含以下一个或两个值的数组
解决方案二:添加 Accessibility Hints
为此,我们添加了一个新属性 accessibilityHint
。设置此属性将允许 Talkback 或 Voiceover 向用户朗读 hint。
accessibilityHint
此属性以 String 的形式接收要读取的 accessibility hint。
在 iOS 上,设置此属性会将相应的原生属性 AccessibilityHint 设置到视图上。如果 iPhone 中启用了 Accessibility Hints,则 Voiceover 将读取该 hint。
在 Android 上,设置此属性会将 hint 的值附加到 accessibility label 的末尾。这种实现的优点是它模仿了 iOS 上 hints 的行为,但这种实现的缺点是这些 hints 无法像在 iOS 上那样在 Android 的设置中关闭。
我们在 Android 上做出此决定的原因是,通常,accessibility hints 与特定操作(例如,click)相对应,并且我们希望保持跨平台行为的一致性。
问题三的解决方案
accessibilityIgnoresInvertColors
我们将 Apple 的 api AccessibilityIgnoresInvertColors 公开给 JavaScript,因此现在当你的视图中不想反转颜色(例如图像)时,你可以将此属性设置为 true,它就不会被反转。
新用法
这些新属性将在 React Native 0.57 版本中提供。
如何升级
如果你目前正在使用 accessibilityComponentType
和 accessibilityTraits
,以下是你升级到新属性可以采取的步骤。
1. 使用 jscodeshift
最简单的用例可以通过运行 jscodeshift 脚本来替换。
这个 脚本 替换了以下实例
accessibilityTraits=“trait”
accessibilityTraits={[“trait”]}
使用
accessibilityRole= “trait”
此脚本还移除了 AccessibilityComponentType
的实例(假设你在任何设置 AccessibilityComponentType
的地方,也会设置 AccessibilityTraits
)。
2. 使用手动 codemod
对于使用 AccessibilityTraits
但没有 AccessibilityRole
对应值的情况,以及将多个 traits 传递到 AccessibilityTraits
的情况,必须手动完成 codemod。
一般来说,
accessibilityTraits= {[“button”, “selected”]}
将手动替换为
accessibilityRole=“button”
accessibilityStates={[“selected”]}
这些属性已经在 Facebook 的代码库中使用。Facebook 的 codemod 非常简单。jscodeshift 脚本修复了我们大约一半的实例,另一半是手动修复的。总的来说,整个过程花费不到几个小时。
希望你发现更新后的 API 有用!并请继续制作无障碍应用程序!#inclusion