视障用户看不见你的 App,却能“听懂”“摸懂”吗?——鸿蒙 Accessibility 无障碍开发深度指南
本文系统讲解了鸿蒙应用的无障碍开发要点。首先介绍了鸿蒙无障碍API的核心功能,包括获取无障碍状态、控制焦点和朗读控件信息。重点讲解了语音播报的实现方式,包括自动朗读控件属性和主动触发播报场景。详细说明了无障碍焦点的控制方法,确保视障用户能顺畅操作。提供了能力检测方案,判断系统是否开启无障碍服务。最后总结了无障碍设计规范,涵盖对比度、触控区域、控件角色等关键要求,并给出了"确认订单&quo
大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~
本文目录:
前言
如果说 UI 设计决定了一个 App 的“颜值”,那 无障碍能力(Accessibility) 就决定了一个 App 的“温度”。
你可能没意识到:你辛辛苦苦写的按钮、动画、布局、交互,对视障用户来说可能都是“空气”。如果没有无障碍支持,你的 App 在他们眼里(准确说是手里)就像是一块锁了屏幕的手机——毫无意义。
所以本章,我们就把鸿蒙的 Accessibility 能力系统地拆开、讲透:
- Accessibility API 到底怎么用?
- 语音播报(TTS)怎么做才不尬?
- 无障碍焦点焦来焦去是怎么控制的?
- 怎么检测用户当前是否启用了无障碍服务?
- 无障碍设计规范到底有哪些“强制、推荐、必踩坑”?
全文含大量实战代码 + 场景讲解,不忽悠、不空谈,可直接落地。
✨ 1. Accessibility API:鸿蒙无障碍能力的大门从这里打开
鸿蒙的无障碍能力由 @ohos.accessibility 模块提供,是整个体系的核心 API。
它能做的事情包括:
- 获取系统无障碍状态
- 控制焦点、朗读控件信息
- 监听无障碍事件
- 开发自定义 Accessibility Extension(无障碍服务)
先来看一个典型的 API 使用示例👇
📌 获取无障碍能力对象
import accessibility from '@ohos.accessibility';
let acManager = accessibility.getAbilityManager();
拿到它,你就能:
- 判断系统无障碍是否开启
- 请求无障碍焦点
- 主动朗读内容
- 监听控件状态变化
🔊 2. 语音播报(TTS):让控件“会说话”,让交互“能听见”
对于视障用户来说,语音是 App 唯一的视觉。
鸿蒙里有两种场景的播报方式:
1)控件自动朗读(推荐)
2)主动触发朗读(必要时使用)
✅ 2.1 自动朗读(基于控件属性)——最友好、最标准
你只需要给控件加上 accessibilityLabel 或 accessibilityDescription,读屏系统就能自动朗读。
📌 示例(JS/ETS)
Button({
type: ButtonType.Capsule,
value: '提交',
})
.accessibilityLabel('提交订单按钮')
.accessibilityDescription('双击提交订单')
只写 value 是远远不够的,必须补充“控件语义”。
对于图片:
Image($r('app.media.icon_cart'))
.accessibilityLabel('购物车')
对于纯装饰图标 不要添加标签,不然读屏会打扰用户。
✅ 2.2 主动朗读(使用 announceForAccessibility)
有些场景必须主动朗读,比如:
- 表单校验失败
- 网络请求成功/失败
- 列表加载完成
- 弹窗出现
📌 示例
acManager.announceForAccessibility('上传完成,文件已保存到本地');
这要求在无障碍模式开启时才播报,否则可能扰民。
🎯 3. 无障碍焦点:视障用户的“鼠标指针”
视觉用户用眼睛定位
→ 视障用户用“无障碍焦点”定位
你需要确保:
- 焦点移动顺序合理
- 焦点不会卡住
- 弹窗/对话框能自动获得焦点
- 列表滚动时焦点不会丢
✅ 3.1 控件可聚焦
直接设置:
Text('按钮')
.focusable(true)
.accessibilityRole('button') // 控件角色
✅ 3.2 手动请求焦点
当页面跳转、弹窗出现时,建议主动将焦点移动到当前关键控件:
acManager.requestFocus(elementId);
其中 elementId 由控件自身属性决定。
✅ 3.3 控制焦点顺序(tabIndex)
鸿蒙支持类似 Web 的 tabIndex 概念:
Button('上一页').tabIndex(1)
Button('下一页').tabIndex(2)
决定了读屏移动顺序。
🔍 4. 能力检测:你的 App 要学会判断“要不要无障碍模式”
不是所有用户都开启无障碍,所以你必须判断系统能力:
📌 检测系统无障碍是否开启
acManager.isEnabled().then(enabled => {
console.info('无障碍是否开启:', enabled);
});
📌 检测用户是否开启了朗读(屏幕阅读器)
acManager.isScreenReaderEnabled().then(status => {
console.info('读屏是否开启:', status);
});
📌 检测是否有特定 Accessibility 服务激活
acManager.getEnabledAbilities().then(list => {
console.info('已启用无障碍服务:', JSON.stringify(list));
});
这个特别适合需要自定义 Accessibility Extension 的 App。
🧱 5. 无障碍设计规范:不做“自闭 UI”,你的 App 要真正友好
以下内容非常关键,很多 App 因为违反这些规范最终被审核拒了👇
🎨 5.1 颜色 / 对比度
文本与背景对比度必须 ≥ 4.5:1
图标与背景 ≥ 3:1
避免:浅灰字 + 更浅灰背景(常见审核雷区)
🔠 5.2 文本不可太小
建议:
- 正文 ≥ 14 sp
- 按钮文字 ≥ 16 sp
- 列表项 ≥ 48 vp 高度
📦 5.3 可触控区域必须 ≥ 48x48 vp
小于这个尺寸就等着用户吐槽吧。
🎯 5.4 所有交互控件必须有:
- 角色(accessibilityRole)
- 标签(accessibilityLabel)
- 动作提示(accessibilityHint)
例如一个删除按钮:
Image($r('app.media.icon_delete'))
.accessibilityRole('button')
.accessibilityLabel('删除')
.accessibilityHint('双击删除该条记录')
🔄 5.5 动画不宜过快或过闪
避免突然闪烁、快速吃帧动画。
对光敏性癫痫用户非常不友好。
🪜 5.6 层级变化时必须播报
如:
- 弹窗打开
- 错误提示出现
- 页面切换完成
使用:
acManager.announceForAccessibility('弹窗已打开')
🧩 6. 实战案例:为“确认订单”页面完成全套无障碍优化
下面给你一个可参考的完整落地方案👇
🧱 页面结构
- 顶部标题 “确认订单”
- 选择地址控件
- 支付方式选择
- 下单按钮
🧿 完整无障碍实现(关键片段)
Column() {
Text('确认订单')
.fontSize(22)
.accessibilityRole('header')
.accessibilityLabel('确认订单页面')
Row() {
Text('收货地址:北京海淀区中关村 32 号')
.accessibilityLabel('收货地址,北京海淀区中关村三十二号')
}
.focusable(true)
.tabIndex(1)
Row() {
Text('支付方式:微信支付')
.accessibilityLabel('当前支付方式:微信支付')
}
.focusable(true)
.tabIndex(2)
Button('提交订单')
.accessibilityRole('button')
.accessibilityLabel('提交订单')
.accessibilityHint('双击提交订单')
.tabIndex(3)
.onClick(() => {
if (!isDataOK) {
acManager.announceForAccessibility('信息不完整,请检查地址和支付方式');
return;
}
submit();
})
}
可落地,不花哨。
🎉 最后的话:Accessibility 不是锦上添花,而是底线
你今天为视障用户优化的每一个无障碍点,
未来都会成为——
- 更高的用户满意度
- 更高的审查通过率
- 更优秀的应用体验
- 更有温度的产品
一句更现实的话:
无障碍做不好,应用审核可能直接卡你。
无障碍做好了,产品才能真正“对所有用户友好”。
如果觉得有帮助,别忘了点个赞+关注支持一下~
喜欢记得关注,别让好内容被埋没~
更多推荐

所有评论(0)