大家好,我是[晚风依旧似温柔],新人一枚,欢迎大家关注~

前言

如果说 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 自动朗读(基于控件属性)——最友好、最标准

你只需要给控件加上 accessibilityLabelaccessibilityDescription,读屏系统就能自动朗读。

📌 示例(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 不是锦上添花,而是底线

你今天为视障用户优化的每一个无障碍点,
未来都会成为——

  • 更高的用户满意度
  • 更高的审查通过率
  • 更优秀的应用体验
  • 更有温度的产品

一句更现实的话:

无障碍做不好,应用审核可能直接卡你。
无障碍做好了,产品才能真正“对所有用户友好”。

如果觉得有帮助,别忘了点个赞+关注支持一下~
喜欢记得关注,别让好内容被埋没~

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐