一个页面在正常字体下看起来很清楚:左边是任务名称,右边是红色的“待处理”,下面还有个只有图标的“更多”按钮。可一旦开启屏幕朗读,用户可能只听见“按钮”“待处理”,却不知道是哪个任务,更不知道点击后会执行什么操作。开发者看到的是视觉层级,辅助技术依赖的却是另一套可被理解、可被操作的语义结构。两者不应该靠运气碰巧一致。

拿一个很普通的巡检任务卡片来说,页面功能只有展示状态、打开详情、切换完成状态三件事,复杂程度并不高。这篇文章不谈某一种炫目的无障碍特效,只围绕三件实际要做的工作:给没有文字的控件补上准确名称;让一组属于同一个任务的信息连贯地朗读;避免装饰元素和隐藏操作打断焦点。做完这些,页面才能从“看得见”逐步变成“听得懂、找得到、用得了”。

朗读语义与焦点组织技术封面

从屏幕上看得到的信息,拆出真正该朗读的内容

考虑下面这样一条任务:空调机房巡检,状态 待处理,预计完成时间 17:30,旁边有一个打开详情的箭头。视觉读者能快速把这四项拼成一句话;屏幕朗读用户如果逐项听到“空调”“待处理”“17:30”“箭头”,信息会碎得很厉害。语义设计的出发点不是把每个字都读一遍,而是把一组能够构成完整动作的信息整理成自然语言,比如“空调机房巡检,待处理,截止十七点三十分”,然后给真正可以点击的控件单独描述其动作。

accessibilityText 可以为组件指定朗读文本,常用于视觉元素缺少文字或者需要补充含义的情况;accessibilityDescription 更适合解释操作后的作用。前者回答“这是什么”,后者回答“怎么用或者操作会发生什么”。如果把两者都写成“按钮”,看起来配置齐全,实际上仍然没有帮助。反过来,也不需要给原本已经很清楚的普通文字叠加一长段同义文本,过度说明会增加朗读成本。

任务卡片的视觉树与朗读语义映射

对于纯装饰的图形、分隔线,朗读它们反而干扰任务。ArkUI 提供 .accessibilityLevel('no') 等属性,允许让不提供信息、也不能交互的组件不被辅助服务感知。需要注意,它不应该随便施加在整个可交互容器上,否则可能连子控件的入口也一起影响。测试时应把内容型、装饰型和交互型组件分开检查,而不能看见重复朗读就把整个 Row 禁掉。

让代码直接表达语义,而不是在测试时临时补标签

下面写一个可单独放入 ArkTS 页面的基础样例。用 @State 驱动完成状态,任务标题和截止时间保持为文本;非交互的信息块整体给出概括性朗读,操作按钮则放在信息块之外,不让 accessibilityGroup(true) 把独立动作错误地吞进去。示例只依赖 ArkUI 基本组件和常见无障碍属性,不需要调用敏感权限。

@Entry
@Component
struct InspectionAccessiblePage {
  @State private done: boolean = false;

  build() {
    Column({ space: 20 }) {
      Text('今日巡检')
        .fontSize(26)
        .fontWeight(FontWeight.Bold)

      Column({ space: 8 }) {
        Text('空调机房巡检')
          .fontSize(20)
        Text(this.done ? '已完成' : '待处理')
          .fontColor(this.done ? Color.Green : Color.Red)
        Text('截止时间:17:30')
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start)
      .accessibilityGroup(true)
      .accessibilityText(
        `空调机房巡检,${this.done ? '已完成' : '待处理'},截止十七点三十分`
      )

      Button(this.done ? '撤销完成' : '标记完成')
        .width('100%')
        .accessibilityDescription(
          this.done ? '将巡检任务恢复为待处理状态' : '将巡检任务标记为已完成'
        )
        .onClick(() => {
          this.done = !this.done;
        })
    }
    .padding(24)
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }
}

这里有一个容易忽略的逻辑:状态标签的颜色不应该是唯一信息。即便红绿两种色值对比足够强,屏幕朗读仍然需要清楚说出“待处理”或“已完成”;在色觉差异、强光、灰阶显示等场景,颜色也可能失去表达力。示例中的状态文字与 done 绑定,就是把状态描述做成页面本身的数据,而不是视觉层的一次装饰。点击后按钮文案和语义都跟着变化,避免出现 UI 已显示“撤销完成”、朗读却仍说“标记完成”的信息错位。

有时开发者会给整张卡片添加 onClick,然后又在卡片里塞一个“更多”按钮。此时如果整个卡片统一设置为无障碍分组,两个动作的语义可能混在一起。更稳妥的设计是:把只读标题、状态、时间归为一个信息组,打开详情与更多操作作为独立可操作项;每个控件有可识别的名称和可理解的结果。技术上能不能把所有控件塞进一个 Row,并不等于辅助服务能不能准确地区分它们。

焦点顺序要能解释页面流程,不能只迎合视觉排版

朗读顺序不一定和人眼扫视路径完全一致,布局重排、容器分组、弹窗出现都可能改变辅助技术感知组件的方式。最稳的基础原则是让逻辑顺序和组件结构一致:先读页面标题,再读任务内容,再进入操作;避免为了视觉上的左右对齐,把操作按钮提前放进一个与内容无关的结构节点。在长列表中,不要每次局部刷新就强制把焦点拉回顶部,否则用户刚找到目标项又得从头听起。

用焦点检查时,不应该只验证“每个按钮都能获得焦点”,还要连续完成一件事。以巡检任务为例,用户应该可以从任务摘要移动到“标记完成”,执行后听到状态变化,再找到下一个任务;返回页面时不应落到已经消失的“完成按钮”上。若删除了一条列表项,需要确定剩余项目的合适焦点目标,不能凭下标复用把焦点跳到完全不同的内容。对于弹层,应检查关闭后是否能够回到具有上下文意义的位置。

朗读焦点顺序与错误分组对照

需要区分键盘焦点与屏幕朗读焦点。.focusable(true)、组件是否可交互、无障碍分组与朗读语义并不是完全等价的机制;不要把给一个装饰 Text 设置可聚焦当成解决“朗读不到”的通用办法。要检查键盘导航,也要开启系统的屏幕朗读服务逐项听读,两条路径分别验证。控件如果有不可用状态,应通过界面状态和相关可访问语义让用户知道它不可执行,而不是仅降低透明度。

建一份可以重复走通的无障碍验收路线

为了让检查落到工程上,可以采用四组小场景,而不需要提前杜撰测量数据。场景一,保持初始“待处理”,开启屏幕朗读,确认任务名称、状态和截止时间连贯可听;场景二,激活“标记完成”,确认按钮文字与任务状态同时更新;场景三,扩大系统字体并切换竖屏或分屏,检查文本没有被省略成无法理解的短句、操作按钮没有被遮挡;场景四,插入或删除列表任务,验证焦点没有突然跳到错误条目。

这些步骤还应该包含反向测试:隐藏一个无意义的分割线,检查是否影响阅读;故意遗漏一个只有图标的按钮名称,看看辅助服务能不能识别功能;将摘要组包住按钮,观察操作入口是否出现难以到达的情况。反向用例能暴露结构错误,但最终应在目标设备、目标系统版本和实际屏幕朗读设置下确认行为。不要把设计稿里的焦点箭头写成某台设备已经输出的真实朗读序列。

屏幕朗读与键盘操作检查路径

再往工程化走一步,可为可重用任务卡片定义明确的语义输入:标题、状态、截止时间、主动作名称和动作结果。UI 布局可换,语义字段保持稳定;状态变化由单一数据源驱动,朗读描述与可见文本从同一份状态生成。这样,当组件从手机单列变成平板双列时,开发者不必额外维护一套容易过期的“无障碍版字符串”,也更容易为产品测试人员提供确定的验收样例。

无障碍适配并不是给界面贴几个标签,而是重新问一遍:一个无法依赖视觉的用户能不能理解这个页面、判断当前位置、完成操作并得到反馈。只要愿意从一张小小的任务卡片做起,把信息组与动作组分清,把焦点流向按任务过程设计,页面的可用性通常就会比简单堆属性强得多。

官方参考:HarmonyOS 屏幕朗读适配指南、ArkUI 高级组件无障碍属性示例。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐