乐闻世界logo
搜索文章和话题

Expo应用的可访问性(Accessibility)如何实现?有哪些最佳实践?

2月21日 16:03

Expo应用的可访问性(Accessibility)是确保所有用户,包括有视觉、听觉、运动或认知障碍的用户,都能有效使用应用的重要方面。Expo和React Native提供了丰富的可访问性API和属性。

可访问性基础:

  1. accessibilityLabel

为屏幕阅读器提供元素的描述。

typescript
<Image source={{ uri: 'https://example.com/image.jpg' }} accessibilityLabel="用户头像" style={{ width: 50, height: 50 }} /> <Button title="提交" accessibilityLabel="提交表单" onPress={handleSubmit} />
  1. accessibilityHint

提供有关元素行为的额外信息。

typescript
<TouchableOpacity accessibilityLabel="查看详情" accessibilityHint="点击查看用户详细信息" onPress={handlePress} > <Text>查看</Text> </TouchableOpacity>
  1. accessibilityRole

指定元素的UI角色。

typescript
<View accessibilityRole="button" accessibilityLabel="确认" onClick={handleConfirm} > <Text>确认</Text> </View>

常用可访问性角色:

  • button:按钮
  • link:链接
  • header:标题
  • text:文本
  • image:图片
  • search:搜索框
  • adjustable:可调节控件
  1. accessibilityState

描述元素的当前状态。

typescript
<CheckBox accessibilityLabel="同意条款" accessibilityState={{ checked: isChecked, disabled: false, }} value={isChecked} onValueChange={setIsChecked} />

可访问性状态:

  • disabled:禁用状态
  • selected:选中状态
  • checked:勾选状态
  • busy:忙碌状态
  • expanded:展开状态
  1. accessibilityValue

描述元素的值。

typescript
<Slider accessibilityLabel="音量" accessibilityValue={{ min: 0, max: 100, now: volume }} value={volume} onValueChange={setVolume} /> <ProgressBar accessibilityLabel="下载进度" accessibilityValue={{ min: 0, max: 100, now: progress }} progress={progress / 100} />

可访问性操作:

  1. accessibilityActions

定义元素支持的可访问性操作。

typescript
<View accessibilityLabel="播放控制" accessibilityActions={[ { name: 'increment', label: '增加音量' }, { name: 'decrement', label: '减少音量' }, { name: 'magicTap', label: '双击播放/暂停' }, ]} onAccessibilityAction={(event) => { switch (event.nativeEvent.actionName) { case 'increment': setVolume((v) => Math.min(v + 10, 100)); break; case 'decrement': setVolume((v) => Math.max(v - 10, 0)); break; case 'magicTap': togglePlayPause(); break; } }} > <Text>音量: {volume}</Text> </View>
  1. onAccessibilityEscape

定义转义操作。

typescript
<Modal visible={isVisible} onAccessibilityEscape={() => setIsVisible(false)} accessibilityViewIsModal={true} > <View> <Text>模态框内容</Text> <Button title="关闭" onPress={() => setIsVisible(false)} /> </View> </Modal>

可访问性属性:

  1. accessible

标记元素为可访问的。

typescript
<View accessible={true}> <Text>这个视图可以被屏幕阅读器访问</Text> </View>
  1. accessibilityElementsHidden

隐藏子元素的可访问性。

typescript
<View accessible={true} accessibilityLabel="容器" accessibilityElementsHidden={isHidden} > <Text>子元素1</Text> <Text>子元素2</Text> </View>
  1. accessibilityIgnoresInvertColors

忽略颜色反转设置。

typescript
<Image source={{ uri: 'https://example.com/chart.jpg' }} accessibilityIgnoresInvertColors={true} style={{ width: 200, height: 200 }} />

焦点管理:

  1. focusable

使元素可聚焦。

typescript
<TextInput focusable={true} accessibilityLabel="用户名输入框" placeholder="请输入用户名" />
  1. accessibilityLiveRegion

标记动态内容区域。

typescript
<Text accessibilityLiveRegion="polite" accessibilityLabel="状态信息" > {statusMessage} </Text>

可访问性事件:

typescript
function useAccessibilityFocus() { const [isFocused, setIsFocused] = useState(false); const handleFocus = () => { setIsFocused(true); console.log('Element focused'); }; const handleBlur = () => { setIsFocused(false); console.log('Element blurred'); }; return { isFocused, handleFocus, handleBlur }; }

语义化组件:

  1. 使用语义化HTML标签(Web)
typescript
// 在Web平台上使用语义化标签 if (Platform.OS === 'web') { return ( <nav accessibilityRole="navigation"> <ul> <li><a href="/home">首页</a></li> <li><a href="/about">关于</a></li> </ul> </nav> ); }
  1. 使用正确的可访问性角色
typescript
// 按钮使用button角色 <TouchableOpacity accessibilityRole="button" accessibilityLabel="提交" onPress={handleSubmit} > <Text>提交</Text> </TouchableOpacity> // 链接使用link角色 <TouchableOpacity accessibilityRole="link" accessibilityLabel="查看详情" onPress={handlePress} > <Text>查看详情</Text> </TouchableOpacity>

最佳实践:

  1. 提供清晰的标签
typescript
// 好的实践 <Button title="提交表单" accessibilityLabel="提交用户注册表单" onPress={handleSubmit} /> // 避免重复 <Button title="提交" accessibilityLabel="提交" // 与title重复 onPress={handleSubmit} />
  1. 使用有意义的提示
typescript
<TouchableOpacity accessibilityLabel="删除项目" accessibilityHint="此操作无法撤销,请谨慎操作" onPress={handleDelete} > <Text>删除</Text> </TouchableOpacity>
  1. 支持键盘导航
typescript
function KeyboardNavigation() { const [focusedIndex, setFocusedIndex] = useState(0); const handleKeyDown = (event) => { if (event.key === 'ArrowDown') { setFocusedIndex((i) => Math.min(i + 1, items.length - 1)); } else if (event.key === 'ArrowUp') { setFocusedIndex((i) => Math.max(i - 1, 0)); } else if (event.key === 'Enter') { items[focusedIndex].onPress(); } }; return ( <View onKeyDown={handleKeyDown}> {items.map((item, index) => ( <TouchableOpacity key={index} accessibilityLabel={item.label} focusable={true} style={[ styles.item, focusedIndex === index && styles.focused, ]} onPress={item.onPress} > <Text>{item.label}</Text> </TouchableOpacity> ))} </View> ); }
  1. 支持屏幕阅读器
typescript
function ScreenReaderSupport() { const isScreenReaderEnabled = useAccessibilityInfo(); return ( <View> {isScreenReaderEnabled ? ( <Text>屏幕阅读器已启用</Text> ) : ( <Text>屏幕阅读器未启用</Text> )} </View> ); }
  1. 测试可访问性
typescript
import { AccessibilityInfo } from 'react-native'; async function testAccessibility() { // 检查屏幕阅读器是否启用 const isScreenReaderEnabled = await AccessibilityInfo.isScreenReaderEnabled(); console.log('Screen reader enabled:', isScreenReaderEnabled); // 检查减少动画设置 const isReduceMotionEnabled = await AccessibilityInfo.isReduceMotionEnabled(); console.log('Reduce motion enabled:', isReduceMotionEnabled); // 监听可访问性变化 AccessibilityInfo.addEventListener( 'screenReaderChanged', (isEnabled) => { console.log('Screen reader changed:', isEnabled); } ); }

可访问性工具:

  1. AccessibilityInfo API
typescript
import { AccessibilityInfo } from 'react-native'; // 获取可访问性信息 const isScreenReaderEnabled = await AccessibilityInfo.isScreenReaderEnabled(); const isReduceMotionEnabled = await AccessibilityInfo.isReduceMotionEnabled(); // 监听变化 AccessibilityInfo.addEventListener('screenReaderChanged', (isEnabled) => { console.log('Screen reader:', isEnabled); }); AccessibilityInfo.addEventListener('reduceMotionChanged', (isEnabled) => { console.log('Reduce motion:', isEnabled); });
  1. 可访问性检查工具
  • iOS:VoiceOver
  • Android:TalkBack
  • Web:屏幕阅读器(NVDA、JAWS等)

常见可访问性问题:

  1. 缺少可访问性标签

    • 为所有交互元素添加accessibilityLabel
    • 为图片提供描述性标签
  2. 焦点管理不当

    • 确保键盘导航顺序合理
    • 提供清晰的焦点指示器
  3. 颜色对比度不足

    • 确保文本和背景有足够的对比度
    • 支持高对比度模式
  4. 动态内容未通知

    • 使用accessibilityLiveRegion标记动态内容
    • 及时通知屏幕阅读器内容变化

通过实施这些可访问性实践,可以确保Expo应用对所有用户都是友好和可用的。

标签:Expo