无障碍功能
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
Android 和 iOS 均提供 API 用于将应用与辅助技术(如系统内置的屏幕阅读器 VoiceOver(iOS)和 TalkBack(Android))集成。React Native 提供互补的 API,让您的应用能够服务所有用户。
Android 和 iOS 的实现方式略有差异,因此 React Native 的无障碍功能实现可能因平台而异。
无障碍属性
accessible
当值为 true 时,表示该视图可被屏幕阅读器和硬件键盘等辅助技术发现。请注意,这并不保证该视图一定会被 VoiceOver 或 TalkBack 聚焦。原因可能包括 VoiceOver 禁止嵌套无障碍元素,或 TalkBack 选择聚焦其父元素等。
默认情况下,所有可触摸元素都具有无障碍特性。
在 Android 上,accessible 会被转换为原生 focusable 属性。在 iOS 上,则转换为原生 isAccessibilityElement 属性。
<View>
<View accessible={true} />
<View />
</View>
在上例中,无障碍焦点仅存在于第一个带有 accessible 属性的子视图上,而不适用于未设置 accessible 属性的父视图或同级视图。
accessibilityLabel
当视图被标记为无障碍元素时,最佳实践是设置 accessibilityLabel 属性,这样使用 VoiceOver 或 TalkBack 的用户就能知道他们选择了什么元素。屏幕阅读器会在选中相关元素时朗读该字符串。
使用方式:在您的 View、Text 或 Touchable 组件上设置 accessibilityLabel 属性为自定义字符串:
<TouchableOpacity
accessible={true}
accessibilityLabel="Tap me!"
onPress={onPress}>
<View style={styles.button}>
<Text style={styles.buttonText}>Press me!</Text>
</View>
</TouchableOpacity>
在上例中,TouchableOpacity 元素的 accessibilityLabel 默认会是 "Press me!"。该标签由所有 Text 子节点通过空格连接构成。
accessibilityLabelledBy Android
引用另一个元素的 nativeID 用于构建复杂表单。
accessibilityLabelledBy 的值应与关联元素的 nativeID 匹配:
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput
accessibilityLabel="input"
accessibilityLabelledBy="formLabel"
/>
</View>
在上例中,当焦点位于 TextInput 时,屏幕阅读器会播报 Input, Edit Box for Label for Input Field。
accessibilityHint
当仅靠无障碍标签无法明确操作结果时,可使用无障碍提示为用户提供额外上下文信息。
在您的 View、Text 或 Touchable 组件上设置 accessibilityHint 属性为自定义字符串:
<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>
在上例中,如果用户在设备的 VoiceOver 设置中启用了提示功能,VoiceOver 会在朗读标签后播报提示。更多关于 accessibilityHint 的指南请参阅 iOS 开发者文档
在上例中,TalkBack 会在标签后朗读提示。目前 Android 无法关闭提示功能。
accessibilityLanguage iOS
通过 accessibilityLanguage 属性,屏幕阅读器能识别朗读元素的标签、值和提示时应使用的语言。提供的字符串值必须遵循 BCP 47 规范。
<View
accessible={true}
accessibilityLabel="Pizza"
accessibilityLanguage="it-IT">
<Text>🍕</Text>
</View>
accessibilityIgnoresInvertColors iOS
屏幕颜色反转是 iOS 和 iPadOS 中为色盲、低视力或视力障碍用户提供的无障碍功能。如果您有不希望在此设置启用时反转的视图(例如照片),请将此属性设为 true。
accessibilityLiveRegion Android
当组件动态变化时,我们需要 TalkBack 通知最终用户。这可通过 accessibilityLiveRegion 属性实现,可设置为 none、polite 或 assertive:
-
none 无障碍服务不应播报此视图的变更。
-
polite 辅助服务应播报此视图的变更
-
assertive 无障碍服务应中断当前语音播报,立即宣布该视图的变更。
<TouchableWithoutFeedback onPress={addOne}>
<View style={styles.embedded}>
<Text>Click me</Text>
</View>
</TouchableWithoutFeedback>
<Text accessibilityLiveRegion="polite">
Clicked {count} times
</Text>
在上述示例中,addOne 方法改变了状态变量 count 的值。当用户触发 TouchableWithoutFeedback 组件时,由于 Text 视图设置了 accessibilityLiveRegion="polite" 属性,TalkBack 会朗读其中的文本内容。
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 生效
<View
accessibilityShowsLargeContentViewer={true}
accessibilityLargeContentTitle="Home Tab">
<Text>Home</Text>
</View>
accessibilityState
描述组件当前状态给辅助技术用户
accessibilityState 是一个对象,包含以下字段:
| Name | Description | Type | Required |
|---|---|---|---|
| disabled | Indicates whether the element is disabled or not. | boolean | No |
| selected | Indicates whether a selectable element is currently selected or not. | boolean | No |
| checked | Indicates the state of a checkable element. This field can either take a boolean or the "mixed" string to represent mixed checkboxes. | boolean or 'mixed' | No |
| busy | Indicates whether an element is currently busy or not. | boolean | No |
| expanded | Indicates whether an expandable element is currently expanded or collapsed. | boolean | No |
使用时,将 accessibilityState 设置为符合特定定义的对象
accessibilityValue
表示组件的当前值。可以是组件值的文本描述,对于基于范围的组件(如滑块和进度条),则包含范围信息(最小值、当前值和最大值)
accessibilityValue 是一个对象,包含以下字段:
| Name | Description | Type | Required |
|---|---|---|---|
| min | The minimum value of this component's range. | integer | Required if now is set. |
| max | The maximum value of this component's range. | integer | Required if now is set. |
| now | The current value of this component's range. | integer | No |
| text | A textual description of this component's value. Will override min, now, and max if set. | string | No |
accessibilityViewIsModal iOS
布尔值,指示 VoiceOver 是否应忽略接收者同级视图中的元素
例如,在包含同级视图 A 和 B 的窗口中,将视图 B 的 accessibilityViewIsModal 设为 true 会使 VoiceOver 忽略视图 A 中的元素。而如果视图 B 包含子视图 C 并将 C 的 accessibilityViewIsModal 设为 true,VoiceOver 仍会处理视图 A 中的元素
accessibilityElementsHidden iOS
布尔值,指示此无障碍元素内包含的子元素是否隐藏
例如,在包含同级视图 A 和 B 的窗口中,将视图 B 的 accessibilityElementsHidden 设为 true 会使 VoiceOver 忽略视图 B 内的元素。这类似于 Android 的 importantForAccessibility="no-hide-descendants" 属性
aria-valuemax
表示基于范围的组件(如滑块和进度条)的最大值
aria-valuemin
表示基于范围的组件(如滑块和进度条)的最小值
aria-valuenow
表示基于范围的组件(如滑块和进度条)的当前值
aria-valuetext
表示组件的文本描述
aria-busy
表示元素正在更新中,辅助技术可能需要等待变更完成后再通知用户。
| Type | Default |
|---|---|
| boolean | false |
aria-checked
表示可勾选元素的状态。该字段可接受布尔值或 "mixed" 字符串(表示混合状态的复选框)。
| Type | Default |
|---|---|
| boolean, 'mixed' | false |
aria-disabled
表示元素可见但处于禁用状态,因此不可编辑或操作。
| Type | Default |
|---|---|
| boolean | false |
aria-expanded
指示可展开元素当前是展开还是折叠状态。
| Type | Default |
|---|---|
| boolean | false |
aria-hidden
表示此无障碍元素内包含的子元素是否隐藏
例如,在包含同级视图 A 和 B 的窗口中,将视图 B 的 aria-hidden 设为 true 会使 VoiceOver 忽略视图 B 内的元素
| Type | Default |
|---|---|
| boolean | false |
aria-label
定义用于标记交互元素的字符串值。
| Type |
|---|
| string |
aria-labelledby Android
标识标记当前元素的关联元素。aria-labelledby 的值应匹配关联元素的 nativeID:
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput aria-label="input" aria-labelledby="formLabel" />
</View>
| Type |
|---|
| string |
aria-live Android
表示元素将被更新,并描述用户代理、辅助技术和用户可预期的实时区域更新类型
-
off 辅助服务不应播报此视图的变更
-
polite 辅助服务应播报此视图的变更
-
assertive 无障碍服务应中断当前语音播报,立即宣布该视图的变更。
| Type | Default |
|---|---|
enum('assertive', 'off', 'polite') | 'off' |
aria-modal iOS
布尔值,指示 VoiceOver 是否应忽略接收器同级视图内的元素。
| Type | Default |
|---|---|
| boolean | false |
aria-selected
指示可选元素当前是否被选中。
| Type |
|---|
| boolean |
importantForAccessibility Android
当两个具有相同父级的重叠UI组件并存时,默认的无障碍焦点可能出现不可预测行为。importantForAccessibility 属性通过控制视图是否触发无障碍事件及是否上报无障碍服务来解决此问题。可选值包括 auto(自动)、yes(是)、no(否)和 no-hide-descendants(最后一个值会强制无障碍服务忽略该组件及其所有子元素)。
<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 当元素无预设角色时使用(与 none 同义)
-
progressbar 用于表示任务进度指示组件
-
radio 用于表示单选按钮。
-
radiogroup 用于表示一组单选按钮。
-
scrollbar 用于表示滚动条。
-
searchbox 当文本框元素需要同时被视为搜索框时使用。
-
slider 用于可"调节"的元素(例如滑块)。
-
spinbutton 用于表示可打开选项列表的按钮。
-
summary 用于在应用首次启动时提供当前状态的快速摘要。
-
switch 用于表示可开关的切换按钮。
-
tab 用于表示标签页。
-
tablist 用于表示标签页列表。
-
timer 用于表示计时器。
-
toolbar 用于表示工具栏(操作按钮或组件的容器)。
无障碍操作
无障碍操作允许辅助技术以编程方式触发组件的操作。组件需要完成以下两个步骤来支持无障碍操作:
-
通过
accessibilityActions属性定义支持的操作列表 -
实现
onAccessibilityAction函数来处理操作请求
accessibilityActions 属性应包含操作对象列表,每个操作对象需包含以下字段:
| Name | Type | Required |
|---|---|---|
| name | string | Yes |
| label | string | No |
操作既可以是标准操作(如点击按钮或调节滑块),也可以是特定组件的自定义操作(如删除邮件)。标准操作和自定义操作都必须提供 name 字段,但标准操作的 label 是可选的。
添加标准操作支持时,name 必须是以下值之一:
-
'magicTap'- 仅限 iOS - 当 VoiceOver 焦点位于组件上或内部时,用户用双指双击 -
'escape'- 仅限 iOS - 当 VoiceOver 焦点位于组件上或内部时,用户执行双指擦除手势(左-右-左) -
'activate'- 激活组件。无论是否使用辅助技术,都应执行相同操作。屏幕阅读器用户双击组件时触发 -
'increment'- 增加可调节组件的值。在 iOS 上,当组件角色为'adjustable'且用户聚焦后上滑时,VoiceOver 会生成此操作。在 Android 上,当用户将无障碍焦点置于组件并按下音量增大键时,TalkBack 会生成此操作 -
'decrement'- 减少可调节组件的值。在 iOS 上,当组件角色为'adjustable'且用户聚焦后下滑时,VoiceOver 会生成此操作。在 Android 上,当用户将无障碍焦点置于组件并按下音量减小键时,TalkBack 会生成此操作 -
'longpress'- 仅限 Android - 当用户将无障碍焦点置于组件上,然后双击并长按屏幕时生成此操作。无论是否使用辅助技术,都应执行相同操作
label 字段对标准操作是可选的(辅助技术通常不使用),对于自定义操作则是包含操作描述的本地化字符串,将展示给用户
要处理操作请求,组件必须实现 onAccessibilityAction 函数。该函数唯一参数是包含待执行操作名称的事件对象。以下来自 RNTester 的示例展示了如何创建定义和处理多个自定义操作的组件
<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 文档。
Sending Accessibility Events Android
有时需要在 UI 组件上触发辅助功能事件(例如自定义视图出现时或为视图设置无障碍焦点)。原生 UIManager 模块为此提供了 'sendAccessibilityEvent' 方法,接收两个参数:视图标签和事件类型。支持的事件类型包括 typeWindowStateChanged、typeViewFocused 和 typeViewClicked。
import {Platform, UIManager, findNodeHandle} from 'react-native';
if (Platform.OS === 'android') {
UIManager.sendAccessibilityEvent(
findNodeHandle(this),
UIManager.AccessibilityEventTypes.typeViewFocused,
);
}
Testing TalkBack Support Android
要启用 TalkBack,请打开 Android 设备或模拟器上的"设置"应用,依次点击"无障碍"→"TalkBack",切换"使用服务"开关即可启用/禁用。
Android 模拟器默认不安装 TalkBack。可通过 Google Play 商店安装:确保选择带 Google Play 商店的模拟器(在 Android Studio 中可用)。
可使用音量键快捷操作开关 TalkBack:进入"设置"→"无障碍",开启顶部的"音量键快捷操作"。
启用快捷操作后,长按两个音量键 3 秒即可启动无障碍工具。
此外也可通过命令行开关 TalkBack:
# 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
Testing VoiceOver Support iOS
要在 iOS/iPadOS 设备启用 VoiceOver:打开"设置"→"通用"→"辅助功能",在"视觉"区域找到 VoiceOver 并切换顶部开关。
在辅助功能设置底部有"辅助功能快捷键",可通过三击 Home 键开关 VoiceOver。
模拟器不支持 VoiceOver,但可使用 Xcode 的 Accessibility Inspector 通过 macOS 的 VoiceOver 测试。注意:实际设备测试更可靠,因 macOS 的 VoiceOver 体验可能不同。