可访问性 API 更新
动机
随着技术进步和移动应用在日常生活中变得越来越重要,创建可访问应用程序的必要性也随之增长。
React Native 有限的可访问性 API 一直是开发者的一大痛点,因此我们对可访问性 API 进行了一些更新,以便更容易地创建包容性移动应用程序。
现有 API 的问题
问题一:两个完全不同但相似的属性 - accessibilityComponentType (Android) 和 accessibilityTraits (iOS)
accessibilityComponentType
和 accessibilityTraits
是两个属性,用于告知 Android 上的 TalkBack 和 iOS 上的 VoiceOver 用户正在与哪种 UI 元素进行交互。这些属性的两个最大问题是:
- 它们是两个不同的属性,用法不同,但目的相同。 在旧 API 中,它们是两个独立的属性(每个平台一个),这不仅不方便,也让许多开发者感到困惑。iOS 上的
accessibilityTraits
允许 17 种不同的值,而 Android 上的accessibilityComponentType
只允许 4 种值。此外,这些值大多没有重叠。甚至这两个属性的输入类型也不同。accessibilityTraits
允许传入一个特性数组或单个特性,而accessibilityComponentType
只允许单个值。 - Android 上的功能非常有限。 使用旧属性,Talkback 只能识别“button”、“radiobutton_checked”和“radiobutton_unchecked”三种 UI 元素。
问题二:不存在的可访问性提示:
可访问性提示可帮助使用 TalkBack 或 VoiceOver 的用户理解当他们对某个可访问性元素执行操作时会发生什么,这些信息仅凭可访问性标签无法明显看出。这些提示可以在设置面板中开启和关闭。以前,React Native 的 API 完全不支持可访问性提示。
问题三:忽略反转颜色:
一些视力受损的用户会在手机上使用反转颜色来获得更大的屏幕对比度。Apple 为 iOS 提供了一个 API,允许开发者忽略某些视图。这样,当用户开启反转颜色设置时,图像和视频就不会失真。React Native 目前不支持此 API。
新 API 的设计
解决方案一:合并 accessibilityComponentType (Android) 和 accessibilityTraits (iOS)
为了解决 accessibilityComponentType
和 accessibilityTraits
之间的混淆,我们决定将它们合并为一个属性。这是有意义的,因为它们在技术上具有相同预期的功能,通过合并它们,开发者在构建可访问性功能时不再需要担心平台特定的复杂性。
背景
在 iOS 上,UIAccessibilityTraits
是一个可以设置在任何 NSObject 上的属性。通过 javascript 属性传递给原生的 17 个特性中的每一个都映射到 Objective-C 中的一个 UIAccessibilityTraits
元素。特性都由一个长整型表示,并且每个设置的特性都会进行 OR 运算。
然而,在 Android 上,AccessibilityComponentType
是一个由 React Native 创建的概念,并不直接映射到 Android 中的任何属性。可访问性由可访问性委托处理。每个视图都有一个默认的可访问性委托。如果您想自定义任何可访问性操作,您必须创建一个新的可访问性委托,覆盖您想要自定义的特定方法,然后将您正在处理的视图的可访问性委托设置为与新委托关联。当开发者设置 AccessibilityComponentType
时,原生代码会根据传入的组件创建一个新的委托,并设置该视图以拥有该可访问性委托。
所做更改
对于我们的新属性,我们希望创建这两个属性的超集。我们决定将新属性主要基于现有属性 accessibilityTraits
进行建模,因为 accessibilityTraits
具有明显更多的值。Android 在这些特性上的功能将通过修改 Accessibility Delegate 来进行 polyfill。
iOS 上的 accessibilityTraits
可以设置为 UIAccessibilityTraits
的 17 个值。然而,我们没有将所有这些值都包含在新属性的可能值中。这是因为设置其中一些特性的效果实际上不是很清楚,而且许多这些值实际上从未使用过。
设置 UIAccessibilityTraits
的值通常有两种目的。它们要么描述 UI 元素扮演的角色,要么描述 UI 元素所处的状态。我们观察到以前属性的大多数用法通常使用一个表示角色的值,并将其与“state selected”、“state disabled”或两者结合。因此,我们决定创建两个新的可访问性属性:accessibilityRole
和 accessibilityState
。
accessibilityRole
新属性 accessibilityRole
用于告知 Talkback 或 Voiceover UI 元素的角色。此新属性可以采用以下值之一:
无
按钮
链接
搜索
图像
键盘键
文本
可调整
标题
摘要
图像按钮
此属性只允许传入一个值,因为 UI 元素通常在逻辑上不会同时拥有多个这些角色。图像和按钮是例外,因此我们添加了一个图像按钮(imagebutton)角色,它是两者的组合。
accessibilityStates
新属性 accessibilityStates
用于告知 Talkback 或 Voiceover UI 元素所处的状态。此属性接受一个包含以下一个或两个值的数组:
已选择
已禁用
解决方案二:添加可访问性提示
为此,我们添加了一个新属性 accessibilityHint
。设置此属性将允许 Talkback 或 Voiceover 向用户朗读提示。
accessibilityHint
此属性以字符串形式接收要读取的可访问性提示。
在 iOS 上,设置此属性将设置视图上相应的原生属性 AccessibilityHint。如果 iPhone 中启用了可访问性提示,Voiceover 将会朗读该提示。
在 Android 上,设置此属性会将提示的值附加到可访问性标签的末尾。这种实现方式的优点是它模仿了 iOS 上提示的行为,但缺点是 Android 上的这些提示无法像 iOS 上那样在设置中关闭。
我们在 Android 上做出此决定的原因是,通常可访问性提示与特定操作(例如点击)相关联,我们希望在不同平台之间保持行为一致。
问题三的解决方案
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. 使用手动代码修改
对于使用 AccessibilityTraits
但没有对应 AccessibilityRole
值的情况,以及将多个特性传递给 AccessibilityTraits
的情况,需要进行手动代码修改。
通常,
accessibilityTraits= {[“button”, “selected”]}
将被手动替换为
accessibilityRole=“button”
accessibilityStates={[“selected”]}
这些属性已在 Facebook 的代码库中使用。Facebook 的代码修改出奇地简单。jscodeshift 脚本修复了我们大约一半的实例,另一半则手动修复。总的来说,整个过程不到几个小时。
希望您能发现更新后的 API 有用!请继续使应用程序更易于访问!#包容性