无障碍功能
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
将默认为“按我!”。标签是通过将所有 Text 节点子元素用空格连接起来构建的。
accessibilityLabelledBy
Android
引用另一个元素的 nativeID,用于构建复杂表单。accessibilityLabelledBy
的值应与相关元素的 nativeID
匹配
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput
accessibilityLabel="input"
accessibilityLabelledBy="formLabel"
/>
</View>
在上面的示例中,当聚焦于 TextInput 时,屏幕阅读器会宣布“输入,输入字段标签的编辑框”。
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 会在标签之后朗读提示。在iOS 开发者文档中阅读更多关于 accessibilityHint
指南的信息
在上面的示例中,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 被触发时,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
。
<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 | 此组件范围的当前值。 | 整数 | 否 |
text | 此组件值的文本描述。如果设置了,将覆盖 min 、now 和 max 。 | 字符串 | 否 |
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
指示元素正在被修改,辅助技术可能需要等待更改完成后再将更新通知用户。
类型 | 默认值 |
---|---|
布尔值 | false |
aria-checked
指示一个可选中元素的状态。该字段可以接受布尔值或字符串“mixed”,表示混合状态的复选框。
类型 | 默认值 |
---|---|
布尔值, 'mixed' | false |
aria-disabled
指示元素可感知但已被禁用,因此不可编辑或操作。
类型 | 默认值 |
---|---|
布尔值 | false |
aria-expanded
指示一个可展开元素当前是展开还是折叠。
类型 | 默认值 |
---|---|
布尔值 | false |
aria-hidden
指示此无障碍元素中包含的无障碍元素是否被隐藏。
例如,在一个包含同级视图 A
和 B
的窗口中,在视图 B
上将 aria-hidden
设置为 true
会导致 VoiceOver 忽略视图 B
中的元素。
类型 | 默认值 |
---|---|
布尔值 | false |
aria-label
定义一个字符串值,用于标记交互元素。
类型 |
---|
字符串 |
aria-labelledby
Android
标识标记应用该属性的元素的元素。aria-labelledby
的值应与相关元素的 nativeID
匹配
<View>
<Text nativeID="formLabel">Label for Input Field</Text>
<TextInput aria-label="input" aria-labelledby="formLabel" />
</View>
类型 |
---|
字符串 |
aria-live
Android
指示元素将更新,并描述用户代理、辅助技术和用户可以从活动区域预期的更新类型。
- off 无障碍服务不应宣布此视图的更改。
- polite 无障碍服务应宣布此视图的更改。
- assertive 无障碍服务应中断正在进行的语音播报,立即宣布此视图的更改。
类型 | 默认值 |
---|---|
枚举('assertive' , 'off' , 'polite' ) | 'off' |
aria-modal
iOS
布尔值,指示 VoiceOver 是否应忽略接收者同级视图中的元素。
类型 | 默认值 |
---|---|
布尔值 | false |
aria-selected
指示一个可选元素当前是否被选中。
类型 |
---|
布尔值 |
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
prop。
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 的示例展示了如何创建一个定义和处理多个自定义操作的组件。
<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’。它接受两个参数:视图标签和事件类型。支持的事件类型包括 typeWindowStateChanged
、typeViewFocused
和 typeViewClicked
。
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,使用
# 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”,然后切换顶部出现的开关。
在“无障碍”设置的最底部,有一个“无障碍快捷方式”。你可以通过三次点击 Home 按钮来切换 VoiceOver。
VoiceOver 无法通过模拟器使用,但你可以使用 Xcode 的“无障碍检查器”通过应用程序使用 macOS 的 VoiceOver。请注意,最好始终使用真实设备进行测试,因为 macOS 的 VoiceOver 可能会导致不同的体验。