在无障碍开发里,按钮和图标是两座绕不开的山。它们是用户操作的核心入口,偏偏又最容易"读不出来"——因为大量按钮根本不用文字,而是靠图标。这篇文章专注讲可交互控件的标注,尤其那几个自定义控件和虚拟按钮区域的坑。

一、为什么按钮是重灾区

按钮在任何应用的语义里都是"用户能点、能操作"的东西。屏幕朗读模式下,视障用户探索界面的基本动作,就是靠焦点在元素间移动,靠朗读判断"这是什么、能不能点、点了会怎样"。

文本按钮天然有显示文本,朗读没问题。真正麻烦的是这几类:

  1. 图标按钮ImageImage 包成的可点击区域,没有任何文字
  2. 自定义控件:开发者用 Canvas、自定义绘制实现的可点击区域,系统根本不认识这是按钮
  3. 虚拟按钮区域:一个大的 Column 里,某个区域点击会触发动作,但它不是标准 Button 组件

官方文档针对这个场景说得很直接:任何可点击的按钮,只要不是文本类控件,就必须给出标注信息,否则屏幕朗读用户无法完成对应功能。

这条是"必须",不是"建议"。

二、标准做法:角色 + 文本

先看一个最标准的图标按钮标注。播放/暂停按钮,前面文章提过,这里再完整过一遍每个属性的作用:

const RESOURCE_STR_PLAY: Resource = $r('sys.media.ohos_ic_public_play');
const RESOURCE_STR_PAUSE: Resource = $r('sys.media.ohos_ic_public_pause');

@Entry
@Component
export struct PlayButton {
  @State isPlaying: boolean = false;

  build() {
    Column() {
      Row() {
        Image(this.isPlaying ? RESOURCE_STR_PAUSE : RESOURCE_STR_PLAY)
          .width(50)
          .height(50)
          .accessibilityRole(AccessibilityRoleType.BUTTON)
          .accessibilityText(this.isPlaying ? '暂停' : '播放')
          .onClick(() => {
            this.isPlaying = !this.isPlaying;
          })
        Text('Good_morning.mp3')
          .margin({ left: 10 })
      }
    }
  }
}

拆解一下,三个无障碍相关的点:

  • accessibilityRole(AccessibilityRoleType.BUTTON):声明"这是个按钮"。这个声明会带来两个效果——系统会按按钮来处理它的焦点和交互语义,朗读时自动追加"按钮"后缀
  • accessibilityText():给朗读内容。注意这里文本跟状态绑定,播放态读"暂停"、暂停态读"播放"
  • 标注不含类型词:没有写"播放按钮",只写了"播放",因为后缀系统会加

三、状态型图标的文本要跟着变

上面例子里最值得强调的是 accessibilityText(this.isPlaying ? '暂停' : '播放') 这一行。

很多开发者图省事,给一个图标按钮设一个固定的无障碍文本,忽略了图标本身是会根据状态改变的。结果就是:

  • 用户看到(假如能看到)图标是"暂停",但听到的是"播放"
  • 或者反过来

这种"视听不一致"对无障碍用户是致命的误导。记住一条原则:图标的视觉状态变了,无障碍文本也要同步变。播放/暂停、收藏/取消收藏、静音/取消静音,全都适用。

四、自定义控件的虚拟按钮区域

这是最容易被遗漏的场景。官方文档特别提醒:用户自定义控件中的虚拟按钮区域也要标注。

什么叫"虚拟按钮区域"?就是你在一个自定义组件里,划出一块区域响应点击,但底层不是标准 Button 组件。比如:

  • 一个 Canvas 画出来的播放器,进度条某个位置可点击
  • 一个自定义游戏板,某个格子可以落子
  • 一个自绘的日历,某个日期格可以选中

这些区域对系统来说就是"一块绘制",系统不知道它是可交互的,更不知道它是什么、点了会干嘛。如果不标注,视障用户完全感知不到这里有个操作入口。

处理这类场景的思路:

  1. 先把这块区域用 accessibilityRole 声明成合适的角色(按钮、可选中项等)
  2. 再用 accessibilityText 描述它的功能和状态
  3. 如果这块区域没有独立的组件承载,要考虑给承载它的容器做标注

五、标注文本的两个禁忌(再强调一次)

按钮标注有两个高频错误,官方文档明确点出来了,这里再强调一遍,因为太常见了。

5.1 不要写控件类型

标注文本里不要出现"按钮"字样。系统会根据 accessibilityRole 自动追加类型。你写了"播放按钮",最终读出来就是"播放按钮,按钮"。

5.2 不要写操作指引

"单指双击即可打开"这种话,属于新手指引的内容。系统会根据控件类型、控件状态、用户是否开启新手引导来自动追加。硬编码进去只会造成信息重复和啰嗦。

六、图标按钮标注清单

把按钮/图标标注总结成一个 checklist,code review 时逐条过:

  • 可点击控件的组件类型是否已通过 accessibilityRole 声明
  • 非文本按钮是否设置了 accessibilityText
  • 状态型图标按钮的无障碍文本是否跟随状态变化
  • 标注文本没有包含控件类型词
  • 标注文本没有包含操作指引
  • 自定义控件中的虚拟按钮区域是否遗漏标注

七、一个额外提醒:点击区域大小

严格说这不算无障碍文本的范畴,但和按钮可用性强相关。低视力用户、老年人、手部活动受限的用户,需要更大的点击区域。图标按钮通常很小,建议扩大它的实际热区(比如给 Image 加足够的 padding,或用不可见的容器扩展点击范围),而不是让用户精确地戳那个 24×24 的图标。

八、总结一下下

按钮和图标标注的原则其实就一条:让视障用户靠听觉获得和明眼用户靠视觉一样的信息。明眼用户看到"一个播放图标",知道"这是个能点的按钮、点了会播放";视障用户就得靠"播放,按钮"这几个字补回同样的认知。

把这篇讲的角色 + 文本 + 状态同步三件事做扎实,可交互控件的无障碍基本就立住了。下一篇进入另一个高频主题——多个组件怎么组合成一个焦点,避免朗读碎片化。

Logo

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

更多推荐