Screen Reader〈屏幕阅读器〉——一种将文本和图形界面元素转换为语音或盲文显示输出的程序,使盲人和低视力用户无需视觉控制即可与设备交互。在移动平台上,主要的屏幕阅读器是iOS上的VoiceOver和Android上的TalkBack。根据世界卫生组织(2023)的数据,屏幕阅读器是全球2.85亿视力障碍人士获取数字技术的主要工具。
要点
屏幕阅读器——一种辅助技术(Assistive Technology, AT),用于解释图形用户界面并以非视觉形式呈现:通过合成语音或触觉盲文显示器。屏幕阅读器是视障人士访问计算机和移动设备的主要手段。
第一批屏幕阅读器出现于20世纪80年代末,用于MS-DOS(例如Vocal-Eyes),后来用于Windows(JAWS、NVDA)。在移动平台上,屏幕阅读器开始在系统级别集成:苹果于2009年在iPhone 3GS中集成了VoiceOver,谷歌在同一年于Android 1.6中集成了TalkBack。到2025年,几乎所有现代智能手机都配备了内置屏幕阅读器,无需安装额外软件。
屏幕阅读器不仅读取屏幕上的文本——它还分析界面的层次结构,确定元素的类型(按钮、链接、标题、输入字段)、状态(启用/禁用、选中/未选中)和相互关系(父级-子级、分组)。这些信息通过语音提示或盲文显示器的触觉感受传递给用户,盲文显示器根据焦点的位置实时更新单元格。
屏幕阅读器与操作系统紧密配合,访问其界面的内部表示——无障碍树(Accessibility Tree)。这种机制在iOS和Android上相同,尽管API名称不同。
屏幕阅读器的主要输出通道是语音合成器(Text-To-Speech, TTS)。当无障碍焦点到达某个元素时,屏幕阅读器提取其文本内容(或开发者指定的描述)并将其发送到TTS引擎。现代TTS引擎,如Apple Speech Synthesis和Google Text-to-Speech,使用神经网络生成自然语音,根据标点符号和内容类型具有正确的语调、停顿和重音。
用户可以调整语速(通常为最大值的60-80%以获得舒适的感知)、音调和音量。某些屏幕阅读器支持多种语音,并根据内容类型在它们之间切换——例如,较慢的语音用于阅读文本,较快的语音用于界面导航。盲文显示器通过蓝牙连接,可同时显示40-80个字符,每次焦点变化时更新行。
屏幕阅读器使用无障碍焦点(Accessibility Focus)的概念,这与标准输入焦点不同。用户通过手势(触摸、滑动)移动无障碍焦点,屏幕阅读器朗读焦点下的元素。导航顺序默认遵循视觉顺序:从左到右、从上到下。开发者可以为复杂布局覆盖此顺序。
屏幕阅读器还支持不同的导航模式,用户通过转子(VoiceOver)或菜单(TalkBack)进行切换:按标题、链接、字符、单词、表单。在标题模式下,屏幕阅读器仅在H1-H6之间移动——这对于长页面和文档的有效导航至关重要。字符模式在输入确认码或复杂密码时提供帮助,逐个朗读每个字符。
在移动平台上,两种屏幕阅读器占据主导地位:iOS上的VoiceOver和Android上的TalkBack。它们具有不同的API、手势和功能,但工作原理相同——读取无障碍树并通过手势控制。
VoiceOver——苹果的屏幕阅读器,内置于iOS、iPadOS和macOS。它使用UIAccessibility API获取元素信息,并支持转子切换导航模式。VoiceOver与iCloud(设置跨设备同步)、Apple Pay(通过Touch ID或Face ID确认支付)和动态文本(字体适应用户设置)集成。
VoiceOver的手势与TalkBack不同:使用双指旋转(转子)、三次点击唤醒屏幕遮蔽(Screen Curtain)和双指双击取消操作。VoiceOver支持自定义转子,开发者通过UIAccessibilityCustomRotor添加——例如,用于绕开标准顺序快速导航到应用的各个部分。
TalkBack——谷歌的屏幕阅读器,属于Android Accessibility Suite的一部分。它使用AccessibilityService和AccessibilityNodeInfo访问界面。TalkBack支持通过L形滑动手势打开全局菜单、元素的自定义操作和用于动态更新的LiveRegion。从Android 14开始,TalkBack获得了一只手手势支持和与Google Assistant的改进集成。
TalkBack的手势系统比VoiceOver更灵活:用户几乎可以将任何手势配置为任何操作。TalkBack还支持屏幕盲文输入(BrailleBack)——用户直接在触摸屏上以每个手指 3x2 的特殊布局用盲文字符输入文本,与屏幕键盘相比显著加快了录入速度。
| 特性 | VoiceOver (iOS) | TalkBack (Android) |
|---|---|---|
| API | UIAccessibility | AccessibilityService |
| 导航 | 转子(2指) | 全局菜单(L形滑动) |
| 语言 | 40+ | 30+ |
| 自定义操作 | UIAccessibilityCustomRotor | AccessibilityDelegate |
| 盲文 | 外接显示器 | BrailleBack + 外接 |
| 动态更新 | UIAccessibility.post | accessibilityLiveRegion |
除了VoiceOver和TalkBack之外,还有一些不太常见的移动屏幕阅读器:Select to Speak(Android,朗读选定区域)、Samsung Voice Assistant(三星One UI设备上替代TalkBack的解决方案)以及特定领域的第三方解决方案——例如,为没有谷歌服务的中国智能手机用户。
屏幕阅读器不能直接访问应用的UI组件。相反,它通过一个中间层——操作系统的无障碍API——工作。操作系统构建无障碍树(Accessibility Tree),屏幕阅读器遍历并分析它。
在iOS上,无障碍树由UIAccessibilityElement对象构建,对应于屏幕上的每个视图。每个元素包含label(主要文本)、traits(元素类型:按钮、标题、链接)、hint(提示)、value(滑块和指示器的当前值)和frame(触摸区域)。系统自动为标准UI组件创建元素,但开发者可以添加和配置它们。
在Android上,无障碍树由AccessibilityNodeInfo对象构建。每个节点包含:text(文本或contentDescription)、className(元素类型)、contentDescription(描述)、stateDescription(状态)、isEnabled、isChecked、isClickable和其他标志。Android还支持AccessibilityAction——屏幕阅读器可以代表用户执行的操作列表:点击、长按、滚动、设置焦点、设置文本。
当界面发生更改时(出现新元素、文本更改、元素变为可见或不可见),操作系统发送AccessibilityEvent。屏幕阅读器订阅这些事件并作出响应:例如,当出现对话框时,屏幕阅读器自动将焦点移到其标题上并朗读内容。
// 在Android上监听无障碍事件
class CustomAccessibilityService : AccessibilityService() {
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
event ?: return
when (event.eventType) {
TYPE_VIEW_CLICKED ->
handleClick(event)
TYPE_WINDOW_STATE_CHANGED ->
handleWindowChange(event)
TYPE_VIEW_TEXT_CHANGED ->
handleTextChange(event)
}
}
}
在iOS上,类似的事件通过UIAccessibility.Notification处理:layoutChanged(布局更改)、screenChanged(全新屏幕)、announcement(任意公告)、pageScrolled(页面滚动)。开发者通过UIAccessibility.post发送这些事件,以便屏幕阅读器正确响应更改。例如,打开模态窗口时,需要发送带有新标题的screenChanged——否则VoiceOver将停留在窗口下方的上一个元素上。
创建无障碍应用不仅是为每个元素添加contentDescription,而是为无障碍交互设计用户体验。基本原则在两个平台上通用,尽管实现方式不同。
所有交互元素都应具有有意义的描述:“发送”按钮应描述为“发送消息”,而不是“按钮”。装饰性元素(分隔线、背景图像、无功能的图标)应对屏幕阅读器隐藏。导航顺序应与屏幕的逻辑流程匹配,而不是视觉布局。文本对比度应至少为主文本4.5:1,大文本3:1(WCAG AA)。
// iOS:复杂元素的正确配置
let customControl = UIControl()
customControl.isAccessibilityElement = true
customControl.accessibilityLabel = "音量"
customControl.accessibilityValue = "75%"
customControl.accessibilityTraits = [
.adjustable,
.button
]
customControl.accessibilityHint =
"增大或减小音量"
// 值更改时更新
func didChangeVolume(newValue: Float) {
customControl.accessibilityValue =
"\\(Int(newValue))%"
UIAccessibility.post(
notification: .layoutChanged,
argument: customControl
)
}
在iOS上,isAccessibilityElement标志为自定义元素启用VoiceOver支持。traits(.adjustable + .button)组合告诉VoiceOver该元素可以通过上下滑动调整并通过双击激活。更改值后必须发送layoutChanged通知——否则VoiceOver将继续朗读旧值。
对于iOS:使用accessibilityElements覆盖阅读顺序,accessibilityCustomActions用于上下文菜单中的额外操作,shouldGroupAccessibilityChildren用于将元素分组为逻辑组。对于SwiftUI,应用.accessibilityLabel()、.accessibilityAddTraits()和.accessibilityRespondsToUserInteraction()修饰符。避免在包含交互性子元素的容器上使用isAccessibilityElement = false——这将会将它们从VoiceOver中隐藏。
对于Android:使用accessibilityTraversalBefore和accessibilityTraversalAfter设置导航顺序,AccessibilityDelegate用于自定义元素,LiveRegion(polite/assertive)用于动态更新。在Compose中,使用带有contentDescription、stateDescription和customActions的.semantics {}修饰符。避免在非交互元素上使用focusable = true——这会给TalkBack创建错误的焦点点并使用户困惑。
使用屏幕阅读器进行测试必须在物理设备上进行。模拟器提供基本概念,但手势和响应速度不同。使用iOS的Accessibility Inspector(Xcode)和Android的Accessibility Scanner自动查找问题。
主要测试场景:注册(填写表单、验证、提交)、搜索和目录导航、下单、密码恢复。每个场景应能在无视觉控制的情况下完成——仅通过屏幕阅读器的语音提示。如果屏幕阅读器用户无法在普通用户的相同时间(±50%)内完成场景,则应用需要改进无障碍性。
常见问题
这是一种朗读智能手机屏幕上所有内容的程序:文本、按钮、通知。用户通过手势控制设备——触摸元素以听到它的名称,双击以激活它。屏幕阅读器用语音替代视觉。
在iOS上——VoiceOver(苹果内置系统屏幕阅读器)。在Android上——TalkBack(属于谷歌Android Accessibility Suite的一部分)。两者都支持手势控制、语音反馈和通过蓝牙连接的盲文显示器。
为所有交互元素设置contentDescription(Android)或accessibilityLabel(iOS)。对屏幕阅读器隐藏装饰性元素。在动态更改时发送通知。在启用屏幕阅读器的物理设备上测试,无需视觉控制。
主要区别在API和手势上。VoiceOver在iOS上使用UIAccessibility和转子进行导航(双指旋转)。TalkBack在Android上使用AccessibilityService和通过L形滑动的全局菜单。工作原理——遍历无障碍树——相同。
屏幕阅读器无法“看到”图片。它读取开发者通过contentDescription(Android)或accessibilityLabel(iOS)设置的文本描述。如果未设置描述,屏幕阅读器可能会读取文件名或只说“图片”——这对用户没有帮助。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。