无障碍功能
Android 和 iOS 都提供了 API,用于将应用程序与辅助技术(如捆绑的屏幕阅读器 VoiceOver (iOS) 和 TalkBack (Android))集成。React Native 具有互补的 API,可让你的应用程序适应所有用户。
Android 和 iOS 在方法上略有不同,因此 React Native 的实现可能因平台而异。
可访问性属性
accessible
当为 true
时,表示该视图是一个可访问性元素。当一个视图是可访问性元素时,它会将其子项分组到一个可选择的组件中。默认情况下,所有可触摸元素都是可访问的。
在 Android 上,react-native View 的 accessible={true}
属性将被转换为原生 focusable={true}
。
<View accessible={true}>
<Text>text one</Text>
<Text>text two</Text>
</View>
在上面的示例中,可访问性焦点仅在具有 accessible
属性的父视图上可用,而 'text one' 和 'text two' 则不可单独访问。
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 将在标签之后读取提示。在 iOS Developer Docs 中阅读更多关于 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 被触发时,由于 Text 视图的 accessibilityLiveRegion="polite"
属性,TalkBack 会读取 Text 视图中的文本。
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
指示元素正在被修改,辅助技术可能希望等到更改完成后再通知用户有关更新。
类型 | 默认值 |
---|---|
布尔值 | 假 |
aria-checked
指示可选中元素的状态。此字段可以采用布尔值或 “mixed” 字符串来表示混合复选框。
类型 | 默认值 |
---|---|
布尔值, 'mixed' | 假 |
aria-disabled
指示元素是可感知的但已禁用,因此不可编辑或以其他方式操作。
类型 | 默认值 |
---|---|
布尔值 | 假 |
aria-expanded
指示可展开元素当前是展开还是折叠状态。
类型 | 默认值 |
---|---|
布尔值 | 假 |
aria-hidden
指示此可访问性元素中包含的可访问性元素是否已隐藏。
例如,在一个包含同级视图 A
和 B
的窗口中,在视图 B
上将 aria-hidden
设置为 true
会导致 VoiceOver 忽略视图 B
中的元素。
类型 | 默认值 |
---|---|
布尔值 | 假 |
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 无障碍服务应中断正在进行的语音播报,以立即宣布对此视图的更改。
类型 | 默认值 |
---|---|
enum('assertive' , 'off' , 'polite' ) | 'off' |
aria-modal
iOS
布尔值,指示 VoiceOver 是否应忽略接收器同级视图中的元素。
类型 | 默认值 |
---|---|
布尔值 | 假 |
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>
在上面的示例中,黄色布局及其后代对于 TalkBack 和所有其他辅助服务都是完全不可见的。因此,我们可以使用具有相同父级的重叠视图,而不会混淆 TalkBack。
onAccessibilityEscape
iOS
将此属性分配给一个自定义函数,当有人执行 “escape” 手势(即两指 Z 形手势)时,将调用该函数。“escape” 函数应在用户界面中按层次结构向后移动。这可能意味着在导航层次结构中向上或向后移动,或者关闭模态用户界面。如果选定的元素没有 onAccessibilityEscape
函数,系统将尝试遍历视图层次结构,直到找到一个有该函数的视图,或者发出 bonk 声以指示无法找到。
onAccessibilityTap
iOS
使用此属性分配一个自定义函数,当有人通过双击已选中的可访问元素来激活它时,将调用该函数。
onMagicTap
iOS
将此属性分配给一个自定义函数,当有人执行 “magic tap” 手势(即两指双击)时,将调用该函数。“magic tap” 函数应执行用户可以在组件上执行的最相关的操作。在 iPhone 上的电话应用程序中,“magic tap” 接听电话或结束当前通话。如果选定的元素没有 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 - 当用户将可访问性焦点放在组件上,然后双击并按住屏幕上的一个手指时,会生成此操作。这应执行相同的操作,无论是否使用辅助技术。
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 组件上触发可访问性事件很有用(即,当自定义视图出现在屏幕上或将可访问性焦点设置为视图时)。Native 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 可能会导致不同的体验。