跳到主要内容

无障碍

Android 和 iOS 都提供了用于将应用程序与辅助技术(如捆绑的屏幕阅读器 VoiceOver (iOS) 和 TalkBack (Android))集成的 API。React Native 具有补充 API,可让你的应用程序适应所有用户。

信息

Android 和 iOS 在其方法上略有不同,因此 React Native 的实现可能因平台而异。

无障碍属性

accessible

当设置为 true 时,表示该视图可被辅助技术(如屏幕阅读器和硬件键盘)发现。请注意,这不一定意味着该视图会被 VoiceOver 或 TalkBack 聚焦。这有许多原因,例如 VoiceOver 不允许嵌套无障碍元素,或者 TalkBack 选择聚焦某个父元素。

默认情况下,所有可触控元素都是可访问的。

在 Android 上,accessible 将被转换为原生 focusable。在 iOS 上,它被转换为原生 isAccessibilityElement

tsx
<View>
<View accessible={true} />
<View />
</View>

在上面的示例中,无障碍焦点仅在具有 accessible 属性的第一个子视图上可用,而对于没有 accessible 的父视图或兄弟视图则不可用。

accessibilityLabel

当视图被标记为可访问时,最好在该视图上设置 accessibilityLabel,以便使用 VoiceOver 或 TalkBack 的人知道他们选择了哪个元素。当关联元素被选中时,屏幕阅读器会朗读此字符串。

要使用,请将 accessibilityLabel 属性设置为你的 View、Text 或 Touchable 上的自定义字符串

tsx
<TouchableOpacity
accessible={true}
accessibilityLabel="Tap me!"
onPress={onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>

在上面的示例中,TouchableOpacity 元素上的 accessibilityLabel 默认为“按我!”。标签是通过将所有 Text 节点子项用空格分隔连接起来构建的。

accessibilityLabelledBy
Android

对另一个元素 nativeID 的引用,用于构建复杂表单。accessibilityLabelledBy 的值应与相关元素的 nativeID 匹配

tsx
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput
accessibilityLabel="input"
accessibilityLabelledBy="formLabel"
/>
</View>

在上面的示例中,当聚焦到 TextInput 时,屏幕阅读器会宣布“输入,输入字段标签的编辑框”。

accessibilityHint

当无障碍标签本身不清楚时,无障碍提示可用于向用户提供有关操作结果的额外上下文。

在你的 View、Text 或 Touchable 上提供 accessibilityHint 属性的自定义字符串

tsx
<TouchableOpacity
accessible={true}
accessibilityLabel="Go back"
accessibilityHint="Navigates to the previous screen"
onPress={onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Back</Text>
</View>
</TouchableOpacity>
iOS

在上面的示例中,如果用户在设备的 VoiceOver 设置中启用了提示,VoiceOver 会在标签之后朗读提示。在 iOS 开发者文档 中阅读有关 accessibilityHint 指南的更多信息

Android

在上面的示例中,TalkBack 会在标签之后朗读提示。目前,Android 上无法关闭提示。

无障碍语言
iOS

通过使用 accessibilityLanguage 属性,屏幕阅读器将理解在朗读元素的标签提示时要使用的语言。提供字符串值必须遵循 BCP 47 规范

tsx
<View
accessible={true}
accessibilityLabel="Pizza"
accessibilityLanguage="it-IT">
<Text>🍕</Text>
</View>

accessibilityIgnoresInvertColors
iOS

反转屏幕颜色是 iOS 和 iPadOS 中为色盲、低视力或视力障碍人士提供的无障碍功能。如果有一个视图你不希望在此设置打开时反转(可能是照片),请将此属性设置为 true

accessibilityLiveRegion
Android

当组件动态更改时,我们希望 TalkBack 提醒最终用户。这可以通过 accessibilityLiveRegion 属性实现。它可以设置为 nonepoliteassertive

  • none 无障碍服务不应宣布此视图的更改。
  • polite 辅助服务应宣布此视图的更改。
  • assertive 辅助服务应中断正在进行的语音,立即宣布此视图的更改。
tsx
<TouchableWithoutFeedback onPress={addOne}>
<View style={styles.embedded}>
<Text>Click me</Text>
</View>
</TouchableWithoutFeedback>
<Text accessibilityLiveRegion="polite">
Clicked {count} times
</Text>

在上面的示例方法 addOne 更改了状态变量 count。当 TouchableWithoutFeedback 被触发时,TalkBack 会朗读 Text 视图中的文本,因为其 accessibilityLiveRegion="polite" 属性。

accessibilityRole

accessibilityRole 向辅助技术用户传达组件的用途。

accessibilityRole 可以是以下之一

  • adjustable 当元素可以“调整”(例如滑块)时使用。
  • alert 当元素包含重要文本需要呈现给用户时使用。
  • button 当元素应被视为按钮时使用。
  • checkbox 当元素表示一个可以选中、未选中或具有混合选中状态的复选框时使用。
  • combobox 当元素表示一个组合框时使用,它允许用户在多个选项中进行选择。
  • header 当元素作为内容部分的标题(例如导航栏的标题)时使用。
  • image 当元素应被视为图像时使用。可以与按钮或链接组合使用。
  • imagebutton 当元素应被视为按钮且也是图像时使用。
  • keyboardkey 当元素作为键盘键时使用。
  • link 当元素应被视为链接时使用。
  • menu 当组件是选项菜单时使用。
  • menubar 当组件是多个菜单的容器时使用。
  • menuitem 用于表示菜单中的项目。
  • none 当元素没有角色时使用。
  • progressbar 用于表示指示任务进度的组件。
  • radio 用于表示单选按钮。
  • radiogroup 用于表示一组单选按钮。
  • scrollbar 用于表示滚动条。
  • search 当文本字段元素也应被视为搜索字段时使用。
  • spinbutton 用于表示打开选项列表的按钮。
  • summary 当应用程序首次启动时,元素可用于提供应用程序当前条件的快速摘要时使用。
  • switch 用于表示可以打开和关闭的开关。
  • tab 用于表示一个标签页。
  • tablist 用于表示一个标签页列表。
  • text 当元素应被视为不可更改的静态文本时使用。
  • timer 用于表示一个计时器。
  • togglebutton 用于表示一个切换按钮。应与 accessibilityState checked 结合使用,以指示按钮是打开还是关闭。
  • toolbar 用于表示一个工具栏(操作按钮或组件的容器)。
  • grid 与 ScrollView、VirtualizedList、FlatList 或 SectionList 结合使用,表示一个网格。为 Android 的 GridView 添加网格内外公告。

accessibilityShowsLargeContentViewer
iOS

一个布尔值,决定当用户在元素上长按时是否显示大内容查看器。

在 iOS 13.0 及更高版本中可用。

accessibilityLargeContentTitle
iOS

当显示大内容查看器时,将用作其标题的字符串。

需要将 accessibilityShowsLargeContentViewer 设置为 true

tsx
<View
accessibilityShowsLargeContentViewer={true}
accessibilityLargeContentTitle="Home Tab">
<Text>Home</Text>
</View>

accessibilityState

向辅助技术用户描述组件的当前状态。

accessibilityState 是一个对象。它包含以下字段

姓名描述类型必需
disabled指示元素是否已禁用。布尔值
selected指示可选元素当前是否已选中。布尔值
checked指示可检查元素的状态。此字段可以接受布尔值或“mixed”字符串来表示混合复选框。布尔值或“mixed”
busy指示元素当前是否繁忙。布尔值
expanded指示可展开元素当前是展开还是折叠。布尔值

要使用,请将 accessibilityState 设置为具有特定定义的对象。

accessibilityValue

表示组件的当前值。它可以是组件值的文本描述,或者对于基于范围的组件(如滑块和进度条),它包含范围信息(最小值、当前值和最大值)。

accessibilityValue 是一个对象。它包含以下字段

姓名描述类型必需
min此组件范围的最小值。整数如果设置了 now,则为必填项。
max此组件范围的最大值。整数如果设置了 now,则为必填项。
now此组件范围的当前值。整数
文本此组件值的文本描述。如果设置了,将覆盖 minnowmax字符串

accessibilityViewIsModal
iOS

一个布尔值,指示 VoiceOver 是否应忽略接收器兄弟视图中的元素。

例如,在一个包含兄弟视图 AB 的窗口中,在视图 B 上将 accessibilityViewIsModal 设置为 true 会导致 VoiceOver 忽略视图 A 中的元素。另一方面,如果视图 B 包含一个子视图 C,并且你在视图 C 上将 accessibilityViewIsModal 设置为 true,VoiceOver 不会忽略视图 A 中的元素。

accessibilityElementsHidden
iOS

一个布尔值,指示给定的无障碍元素及其包含的任何无障碍元素是否隐藏。

例如,在一个包含兄弟视图 AB 的窗口中,在视图 B 上将 accessibilityElementsHidden 设置为 true 会导致 VoiceOver 忽略视图 B 及其包含的任何元素。这类似于 Android 属性 importantForAccessibility="no-hide-descendants"

aria-valuemax

表示基于范围的组件(如滑块和进度条)的最大值。

aria-valuemin

表示基于范围的组件(如滑块和进度条)的最小值。

aria-valuenow

表示基于范围的组件(如滑块和进度条)的当前值。

aria-valuetext

表示组件的文本描述。

aria-busy

表示元素正在被修改,辅助技术可能需要等待更改完成才能将更新通知用户。

类型默认
布尔值false

aria-checked

指示可检查元素的状态。此字段可以接受布尔值或“mixed”字符串来表示混合复选框。

类型默认
布尔值,'mixed'false

aria-disabled

表示元素可感知但已禁用,因此不可编辑或以其他方式操作。

类型默认
布尔值false

aria-expanded

指示可展开元素当前是展开还是折叠。

类型默认
布尔值false

aria-hidden

表示元素是否对辅助技术隐藏。

例如,在一个包含兄弟视图 AB 的窗口中,将视图 Baria-hidden 设置为 true 会导致 VoiceOver 忽略 B 元素及其子元素。

类型默认
布尔值false

aria-label

定义一个可用于命名元素的字符串值。

类型
字符串

aria-labelledby
Android

标识标记它所应用的元素的元素。aria-labelledby 的值应与相关元素的 nativeID 匹配

tsx
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput aria-label="input" aria-labelledby="formLabel" />
</View>
类型
字符串

aria-live
Android

指示元素将更新并描述用户代理、辅助技术和用户可以从活动区域预期的更新类型。

  • off 辅助服务不应宣布此视图的更改。
  • polite 辅助服务应宣布此视图的更改。
  • assertive 辅助服务应中断正在进行的语音,立即宣布此视图的更改。
类型默认
enum('assertive', 'off', 'polite')'off'

aria-modal
iOS

布尔值,指示 VoiceOver 是否应忽略接收器兄弟视图中的元素。

类型默认
布尔值false

aria-selected

指示可选元素当前是否已选中。

类型
布尔值

experimental_accessibilityOrder

实验性 🧪

此 API 具有实验性。 实验性 API 可能包含 bug,并且很可能在 React Native 的未来版本中发生变化。请勿在生产环境中使用。

注意

为简洁起见,以下示例中省略了布局,尽管它决定了默认的焦点顺序。假设文档顺序与布局顺序匹配。

experimental_accessibilityOrder 允许你定义辅助技术聚焦子组件的顺序。它是一个 nativeID 数组,这些 ID 设置在你正在控制顺序的组件上。例如

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View accessible={true} nativeID="C"/>
</View>

辅助技术将聚焦 nativeIDBView,然后是 C,然后是 A

experimental_accessibilityOrder 不会为它引用的组件“开启”无障碍功能,这仍然需要完成。因此,如果我们在上面的 C 上移除 accessible={true} 如下

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View nativeID="C"/>
</View>

那么新顺序将是 B 然后是 A,即使 C 仍在 experimental_accessibilityOrder 中。

然而,experimental_accessibilityOrder 将“关闭”它未引用的组件的无障碍功能。

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View accessible={true} nativeID="C"/>
<View accessible={true} nativeID="D"/>
</View>

上面示例的顺序将是 BCAD 永远不会被聚焦。从这个意义上说,experimental_accessibilityOrder穷尽的

将非可访问组件包含在 experimental_accessibilityOrder 中仍然有正当理由。考虑

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View nativeID="C">
<View accessible={true} nativeID="D"/>
<View accessible={true} nativeID="E"/>
<View accessible={true} nativeID="F"/>
</View>
</View>

焦点顺序将是 BDEFA。即使 DEF 没有在 experimental_accessibilityOrder 中直接引用,C 是直接引用的。在此实例中,C 是一个无障碍容器 - 它包含可访问元素,但本身不可访问。如果一个无障碍容器在 experimental_accessibilityOrder 中被引用,则应用其包含元素的默认顺序。从这个意义上说,experimental_accessibilityOrder可嵌套的

experimental_accessibilityOrder 也可以引用另一个具有 experimental_accessibilityOrder 的组件

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View nativeID="C" experimental_accessibilityOrder={['F', 'E', 'D']}>
<View accessible={true} nativeID="D"/>
<View accessible={true} nativeID="E"/>
<View accessible={true} nativeID="F"/>
</View>
</View>

焦点顺序将是 BFEDA

一个组件不能同时是无障碍容器和无障碍元素 (accessible={true})。所以如果我们有

<View experimental_accessibilityOrder={['B', 'C', 'A']}>
<View accessible={true} nativeID="A"/>
<View accessible={true} nativeID="B"/>
<View accessible={true} nativeID="C" experimental_accessibilityOrder={['F', 'E', 'D']}>
<View accessible={true} nativeID="D"/>
<View accessible={true} nativeID="E"/>
<View accessible={true} nativeID="F"/>
</View>
</View>

焦点顺序将是 BCADEF 不再在容器中,因此 experimental_accessibilityOrder 的穷尽性质意味着它们将被排除。

importantForAccessibility
Android

在两个具有相同父级的重叠 UI 组件的情况下,默认的无障碍焦点可能会有不可预测的行为。importantForAccessibility 属性将通过控制视图是否触发无障碍事件以及是否向无障碍服务报告来解决此问题。它可以设置为 autoyesnono-hide-descendants(最后一个值将强制无障碍服务忽略该组件及其所有子级)。

tsx
<View style={styles.container}>
<View
style={[styles.layout, {backgroundColor: 'green'}]}
importantForAccessibility="yes">
<Text>First layout</Text>
</View>
<View
style={[styles.layout, {backgroundColor: 'yellow'}]}
importantForAccessibility="no-hide-descendants">
<Text>Second layout</Text>
</View>
</View>

在上面的示例中,yellow 布局及其子级对 TalkBack 和所有其他无障碍服务完全不可见。因此,我们可以使用具有相同父级的重叠视图而不会混淆 TalkBack。

onAccessibilityEscape
iOS

将此属性分配给一个自定义函数,当有人执行“退出”手势(即两指 Z 形手势)时,该函数将被调用。退出函数应在用户界面中分层后退。这可能意味着在导航层次结构中向上或向后移动,或关闭模态用户界面。如果选定的元素没有 onAccessibilityEscape 函数,系统将尝试遍历视图层次结构,直到找到一个具有该函数的视图,或者发出声音表示无法找到。

onAccessibilityTap
iOS

使用此属性分配一个自定义函数,当有人在选中可访问元素后通过双击激活它时,该函数将被调用。

onMagicTap
iOS

将此属性分配给一个自定义函数,当有人执行“魔术点击”手势(即两指双击)时,该函数将被调用。魔术点击函数应执行用户可以在组件上采取的最相关操作。在 iPhone 的“电话”应用程序中,魔术点击接听电话或结束当前通话。如果选定的元素没有 onMagicTap 函数,系统将遍历视图层次结构,直到找到一个具有该函数的视图。

role

role 传达组件的用途,并优先于 accessibilityRole 属性。

role 可以是以下之一

  • alert 当元素包含重要文本需要呈现给用户时使用。
  • button 当元素应被视为按钮时使用。
  • checkbox 当元素表示一个可以选中、未选中或具有混合选中状态的复选框时使用。
  • combobox 当元素表示一个组合框时使用,它允许用户在多个选项中进行选择。
  • grid 与 ScrollView、VirtualizedList、FlatList 或 SectionList 结合使用,表示一个网格。为 Android 的 GridView 添加网格内外公告。
  • heading 当元素作为内容部分的标题(例如导航栏的标题)时使用。
  • img 当元素应被视为图像时使用。例如,可以与按钮或链接组合使用。
  • link 当元素应被视为链接时使用。
  • list 用于标识项目列表。
  • listitem 用于标识列表中的项目。
  • menu 当组件是选项菜单时使用。
  • menubar 当组件是多个菜单的容器时使用。
  • menuitem 用于表示菜单中的项目。
  • none 当元素没有角色时使用。
  • presentation 当元素没有角色时使用。
  • progressbar 用于表示指示任务进度的组件。
  • radio 用于表示单选按钮。
  • radiogroup 用于表示一组单选按钮。
  • scrollbar 用于表示滚动条。
  • searchbox 当文本字段元素也应被视为搜索字段时使用。
  • slider 当元素可以“调整”(例如滑块)时使用。
  • spinbutton 用于表示打开选项列表的按钮。
  • summary 当应用程序首次启动时,元素可用于提供应用程序当前条件的快速摘要时使用。
  • switch 用于表示可以打开和关闭的开关。
  • tab 用于表示一个标签页。
  • tablist 用于表示一个标签页列表。
  • timer 用于表示一个计时器。
  • toolbar 用于表示一个工具栏(操作按钮或组件的容器)。

无障碍操作

无障碍操作允许辅助技术以编程方式调用组件的操作。为了支持无障碍操作,组件必须执行两件事

  • 通过 accessibilityActions 属性定义它支持的操作列表。
  • 实现 onAccessibilityAction 函数以处理操作请求。

accessibilityActions 属性应包含一个操作对象列表。每个操作对象应包含以下字段

姓名类型必需
name字符串
label字符串

操作既可以表示标准操作,例如点击按钮或调整滑块,也可以表示特定于给定组件的自定义操作,例如删除电子邮件消息。name 字段对于标准操作和自定义操作都是必需的,但 label 对于标准操作是可选的。

添加对标准操作的支持时,name 必须是以下之一

  • 'magicTap' - 仅限 iOS - 当 VoiceOver 焦点在组件上或组件内部时,用户用两根手指双击。
  • 'escape' - 仅限 iOS - 当 VoiceOver 焦点在组件上或组件内部时,用户执行了两指擦除手势(左、右、左)。
  • 'activate' - 激活组件。这应该在有或没有辅助技术的情况下执行相同的操作。当屏幕阅读器用户双击组件时启用。
  • 'increment' - 增加可调整组件。在 iOS 上,当组件具有 'adjustable' 角色且用户将其聚焦并向上滑动时,VoiceOver 会生成此操作。在 Android 上,当用户将无障碍焦点放在组件上并按下音量调高按钮时,TalkBack 会生成此操作。
  • 'decrement' - 减少可调整组件。在 iOS 上,当组件具有 'adjustable' 角色且用户将其聚焦并向下滑动时,VoiceOver 会生成此操作。在 Android 上,当用户将无障碍焦点放在组件上并按下音量调低按钮时,TalkBack 会生成此操作。
  • 'longpress' - 仅限 Android - 当用户将无障碍焦点放在组件上,然后双击并在屏幕上按住一根手指时,会生成此操作。这应该在有或没有辅助技术的情况下执行相同的操作。
  • 'expand' - 仅限 Android - 此操作“展开”组件,以便 TalkBack 将宣布“已展开”提示。
  • 'collapse' - 仅限 Android - 此操作“折叠”组件,以便 TalkBack 将宣布“已折叠”提示。

label 字段对于标准操作是可选的,并且通常不被辅助技术使用。对于自定义操作,它是一个本地化字符串,包含要呈现给用户的操作描述。

为了处理操作请求,组件必须实现 onAccessibilityAction 函数。此函数的唯一参数是一个事件,其中包含要执行的操作的名称。以下来自 RNTester 的示例展示了如何创建一个定义和处理多个自定义操作的组件。

tsx
<View
accessible={true}
accessibilityActions={[
{name: 'cut', label: 'cut'},
{name: 'copy', label: 'copy'},
{name: 'paste', label: 'paste'},
]}
onAccessibilityAction={event => {
switch (event.nativeEvent.actionName) {
case 'cut':
Alert.alert('Alert', 'cut action success');
break;
case 'copy':
Alert.alert('Alert', 'copy action success');
break;
case 'paste':
Alert.alert('Alert', 'paste action success');
break;
}
}}
/>

检查屏幕阅读器是否启用

AccessibilityInfo API 允许你确定屏幕阅读器当前是否处于活动状态。有关详细信息,请参阅 AccessibilityInfo 文档

发送无障碍事件
Android

有时,在 UI 组件上触发无障碍事件很有用(例如,当自定义视图出现在屏幕上或将无障碍焦点设置到视图时)。原生 UIManager 模块为此目的公开了一个方法“sendAccessibilityEvent”。它接受两个参数:视图标签和事件类型。支持的事件类型有 typeWindowStateChangedtypeViewFocusedtypeViewClicked

tsx
import {Platform, UIManager, findNodeHandle} from 'react-native';

if (Platform.OS === 'android') {
UIManager.sendAccessibilityEvent(
findNodeHandle(this),
UIManager.AccessibilityEventTypes.typeViewFocused,
);
}

测试 TalkBack 支持
Android

要启用 TalkBack,请在你的 Android 设备或模拟器上进入“设置”应用程序。点击“无障碍”,然后点击“TalkBack”。切换“使用服务”开关以启用或禁用它。

Android 模拟器默认不安装 TalkBack。你可以通过 Google Play 商店在模拟器上安装 TalkBack。请务必选择已安装 Google Play 商店的模拟器。这些在 Android Studio 中可用。

你可以使用音量键快捷方式切换 TalkBack。要打开音量键快捷方式,请进入“设置”应用程序,然后进入“无障碍”。在顶部,打开音量键快捷方式。

要使用音量键快捷方式,请同时按下两个音量键 3 秒钟以启动无障碍工具。

此外,如果你愿意,可以使用命令行切换 TalkBack

shell
# disable
adb shell settings put secure enabled_accessibility_services com.android.talkback/com.google.android.marvin.talkback.TalkBackService

# enable
adb shell settings put secure enabled_accessibility_services com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService

测试 VoiceOver 支持
iOS

要在你的 iOS 或 iPadOS 设备上启用 VoiceOver,请进入“设置”应用程序,点击“通用”,然后点击“无障碍”。在那里你会找到许多可供人们启用其设备以使其更易于使用的工具,包括 VoiceOver。要启用 VoiceOver,请在“视觉”下点击 VoiceOver 并切换顶部出现的开关。

在“无障碍”设置的最底部,有一个“无障碍快捷方式”。你可以使用它通过三击主页按钮来切换 VoiceOver。

VoiceOver 无法通过模拟器使用,但你可以使用 Xcode 的无障碍检查器通过应用程序使用 macOS 的 VoiceOver。请注意,最好始终使用设备进行测试,因为 macOS 的 VoiceOver 可能会导致不同的体验。

其他资源