首页 / 资讯中心 / 文章详情

HarmonyOS ArkUI 图标按钮无障碍:从“只念按钮”到完整页面读屏检查【鸿蒙心迹】

HarmonyOS ArkUI 图标按钮无障碍:从“只念按钮”到完整页面读屏检查【鸿蒙心迹】 ★ FEATURED ARTICLE
你是不是也在想——“鸿蒙这么火我能不能学会”答案是当然可以这个专栏专为零基础小白设计不需要编程基础也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例手把手带你从安装开发工具开始一步步学会开发自己的鸿蒙应用。不管你是学生、上班族、打算转行还是单纯对技术感兴趣只要你愿意花一点时间就能在这里搞懂鸿蒙开发并做出属于自己的App关注本专栏《零基础学鸿蒙开发》一起变强每一节内容我都会持续更新配图代码解释全都有欢迎点个关注不走丢我是小白酷爱学习我们一起上路 全文目录前言一、为什么只有一个图标时读屏很难知道它是什么意思二、无障碍文本和无障碍说明不是一回事三、accessibility group一条业务信息不要拆成五次朗读四、选中和禁用状态不能只靠颜色表达五、图片按钮应该把朗读信息放在哪里六、表单输入区不要只检查“能不能输入”七、把这些点放进一个最小页面八、做一次完整页面读屏检查容易理解错的几个地方开发经验总结前言一个只有图标、没有文字的操作按钮对视觉用户来说可能很直观心形代表收藏垃圾桶代表删除分享箭头代表分享。但切到屏幕朗读后如果组件只暴露了“按钮”这个类型而没有可朗读的名称用户得到的信息就可能只剩下“按钮”。这类问题并不需要重做页面。ArkUI 已提供无障碍文本、无障碍说明、无障碍分组、无障碍重要性等通用属性对于选择状态还可以优先使用 Checkbox、Toggle 等本身具有状态语义的组件。HarmonyOS 7 对应 API 26.0.0本文以 HarmonyOS 7 / API 26 为基线做一次从图标按钮到表单区域的完整页面无障碍补全。华为官方也已经提供“提升屏幕朗读无障碍体验”专题覆盖按钮标注、多维信息整体朗读、控件状态变化、自定义控件播报状态等场景。一、为什么只有一个图标时读屏很难知道它是什么意思先看一个常见写法Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) } .onClick(() { // 收藏操作 })这里视觉上已经是一个完整按钮但Image本身没有“收藏”这段文字。官方对无障碍文本的定义很明确当组件没有可供屏幕朗读的文本信息时可以通过accessibilityText提供无障碍文本如果组件本身已有文本设置的无障碍文本会作为朗读内容使用。accessibilityDescription则用于进一步解释操作及可能产生的后果。HarmonyOS 7 的 ArkUI API 变更资料中仍可以确认CommonMethod提供accessibilityGroup(value: boolean)、accessibilityText(value: string)、accessibilityDescription(value: string)、accessibilityLevel(value: string)等接口。所以这个问题的关键并不是“给图标起一个文件名”而是让真正承担交互的组件向无障碍服务暴露完整语义。可以改成Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(收藏) .accessibilityDescription(将当前内容加入收藏) .onClick(() { // 收藏操作 })这里真正需要关注三件事。第一accessibilityText(收藏)回答的是“这是什么”。第二accessibilityDescription(将当前内容加入收藏)回答的是“执行后会发生什么”。第三图标只是按钮内部的视觉内容因此示例通过accessibilityLevel(no)避免它再成为一个没有独立交互价值的朗读目标。无障碍重要性支持auto、yes、no和no-hide-descendants等取值其中no表示当前组件不被无障碍辅助服务识别no-hide-descendants则会同时忽略当前组件及全部子组件。这里也能看出一个设计原则**不要把 Image 本身加上onClick就直接当按钮使用。**如果交互语义本来就是按钮优先使用Button承载点击行为再把Image放进 Button。官方 Button 指南明确支持 Button 作为容器添加图片、文字等子组件。二、无障碍文本和无障碍说明不是一回事accessibilityText和accessibilityDescription很容易被写成两句差不多的话.accessibilityText(删除) .accessibilityDescription(删除按钮)这种配置虽然有信息但第二句没有增加多少价值。更合理的思路是.accessibilityText(删除) .accessibilityDescription(删除当前草稿)对于风险更高的操作还可以把后果写清楚.accessibilityText(删除) .accessibilityDescription(删除当前草稿操作前会再次确认)官方文档对二者的职责划分也是如此无障碍文本负责提供组件本身缺少的文字信息无障碍说明用于补充仅靠组件属性和无障碍文本无法得知的操作后果存在说明时朗读会在组件文本之后继续播报说明。因此不建议把所有按钮都机械补成“XX按钮点击XX”。真正需要补的是用户无法从名称本身判断的信息。三、accessibility group一条业务信息不要拆成五次朗读页面中的另一个典型问题是一张信息卡片由多个Text拼成订单 待支付 68 元 今天 18:00 前支付如果这些信息属于同一个不可独立操作的业务单元让读屏逐个停留用户需要多次滑动才能知道这张卡片表达了什么。这种场景可以考虑无障碍分组Row() { Column({ space: 4 }) { Text(订单) Text(待支付) Text(68 元) Text(今天 18:00 前支付) } .alignItems(HorizontalAlign.Start) } .width(100%) .padding(16) .accessibilityGroup(true) .accessibilityText(订单待支付金额68元今天18点前支付)accessibilityGroup(true)的含义是把当前组件和子组件作为一个整体的可选中组件无障碍服务不再分别关注它的子组件内容。这很好用但也很容易用错。如果卡片里面还有“支付”“取消”两个真正需要独立操作的按钮就不应该简单把整张卡片全部 group 掉。否则子组件不再作为独立的无障碍目标反而可能损失操作入口。所以分组的判断标准不是“它们视觉上在一个 Row 里”而是这些子节点在无障碍交互中是否应该被当成一个整体。四、选中和禁用状态不能只靠颜色表达视觉页面经常用颜色区分状态蓝色表示选中灰色表示禁用实心心形表示已收藏。问题在于颜色和图标变化并不等于无障碍语义发生了变化。对于真正属于“选择”的交互优先考虑使用具有对应状态模型的标准组件。例如 Checkbox 从 API version 8 开始提供select(value: boolean)用来设置选中状态onChange返回状态变化结果。HarmonyOS 当前文档同时明确提供enabled控制组件是否可交互。例如State private receiveNotice: boolean false; Checkbox({ name: receiveNotice }) .select(this.receiveNotice) .accessibilityText(接收更新通知) .onChange((value: boolean) { this.receiveNotice value; })如果业务就是一个勾选项不建议为了视觉效果自己画一个Image再维护一份State最后还要额外想办法把状态暴露给无障碍系统。禁用状态同理。不要只是把按钮改成灰色Button(提交) .enabled(this.canSubmit)官方对enabled(false)的行为说明是组件进入不可交互状态不再响应点击、触摸、拖拽、按键、焦点和鼠标事件同时 UI 状态也会变化。对于自定义 Native ArkUI 节点官方还提供了ArkUI_AccessibilityState用于描述选中、勾选、禁用等无障碍状态该结构从 API version 12 开始提供。本文的 ArkTS 页面没有必要为了普通 Checkbox/Button 再下沉到 Native API但这个接口也说明了一个核心原则状态是无障碍信息的一部分而不仅仅是视觉样式。具体的屏幕朗读措辞可能随系统版本、组件和辅助服务而不同因此实际项目仍应在目标 HarmonyOS 版本和目标设备上逐项验证而不是根据界面颜色推断读屏结果。五、图片按钮应该把朗读信息放在哪里再看一个更完整的图片按钮Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_share)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(分享) .accessibilityDescription(打开分享面板) .onClick(() { // 打开分享面板 })这里把无障碍文本设置在Button上而不是设置在内部Image上。原因很直接真正可以执行操作的是 Button。Image 只是它的视觉表现。如果把 Image 和 Button 都做成可识别节点就可能出现两个焦点如果只给 Image 写“分享”而 Button 本身仍没有名称组件树中的交互语义又会变得割裂。ArkUI 官方针对无障碍场景还提供了代码检查规则要求自定义交互组件通过accessibilityRole声明组件类型例如按钮、编辑框。对于本文这种标准Button场景可以直接使用标准组件如果业务必须用Column、Row等组件自己实现交互则还需要额外关注角色语义而不是只有一个onClick就结束。六、表单输入区不要只检查“能不能输入”一个页面做无障碍检查时输入框经常被漏掉因为TextInput本身已经能够获得焦点、输入文字看起来没有问题。但读屏用户还需要知道三个信息这是哪个字段、现在是什么状态、填写它有什么要求。最小表单可以这样组织State private email: string ; Column({ space: 8 }) { Text(邮箱地址) .fontSize(14) TextInput({ text: this.email, placeholder: nameexample.com }) .width(100%) .accessibilityDescription(用于接收更新通知) .onChange((value: string) { this.email value; }) Button(提交) .enabled(this.email.length 0) .accessibilityDescription( this.email.length 0 ? 提交当前表单 : 请先填写邮箱地址 ) } .alignItems(HorizontalAlign.Start)这里特意保留了可见的“邮箱地址”标签而不是只依赖 placeholder。placeholder 是输入提示并不应该承担页面上全部的字段说明。另一个需要谨慎的地方是accessibilityText官方定义指出当组件本身已有文本信息时无障碍文本可以替代原有文本进行播报。 对编辑组件来说如果随意用固定的accessibilityText(邮箱地址)覆盖内容就需要特别检查输入后的实际朗读结果。因此表单不要套用“所有组件都加 accessibilityText”的机械规则而应该以最终读屏顺序和实际播报内容为准。七、把这些点放进一个最小页面下面代码把图标按钮、信息分组、Checkbox 状态、输入框和禁用按钮放在同一页。代码按照 HarmonyOS 7 / API 26 当前官方接口组织其中ic_favorite、ic_share是示例应用自己的图片资源名需要在工程resources/base/media中准备对应资源。Entry Component struct AccessibilityDemo { State private receiveNotice: boolean false; State private email: string ; build() { Scroll() { Column({ space: 20 }) { Text(文章详情) .fontSize(24) .fontWeight(FontWeight.Bold) Row({ space: 12 }) { Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(收藏) .accessibilityDescription(将当前文章加入收藏) .onClick(() { // 收藏业务 }) Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_share)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(分享) .accessibilityDescription(打开分享面板) .onClick(() { // 分享业务 }) } Row() { Column({ space: 4 }) { Text(阅读进度) Text(第 3 章) Text(约 8 分钟) } .alignItems(HorizontalAlign.Start) } .width(100%) .padding(16) .accessibilityGroup(true) .accessibilityText(阅读进度第3章约8分钟) Row({ space: 8 }) { Checkbox({ name: receiveNotice }) .select(this.receiveNotice) .accessibilityText(接收更新通知) .onChange((value: boolean) { this.receiveNotice value; }) Text(接收更新通知) } .width(100%) Column({ space: 8 }) { Text(邮箱地址) .fontSize(14) TextInput({ text: this.email, placeholder: nameexample.com }) .width(100%) .accessibilityDescription(用于接收更新通知) .onChange((value: string) { this.email value; }) } .alignItems(HorizontalAlign.Start) .width(100%) Button(提交) .width(100%) .enabled(this.email.length 0) .accessibilityDescription( this.email.length 0 ? 提交当前表单 : 请先填写邮箱地址 ) } .padding(20) .width(100%) .alignItems(HorizontalAlign.Start) } .width(100%) .height(100%) } }这个示例没有调用 Accessibility Kit 的状态查询或主动播报接口也没有新增module.json5权限。这里解决的是 ArkUI 组件自身的无障碍语义问题主要依赖 ArkUI 通用属性和标准组件。Accessibility Kit 更偏向无障碍状态查询、无障碍事件发送等能力ArkUI 则负责组件层面的无障碍文本、说明等信息。八、做一次完整页面读屏检查代码写完并不代表无障碍检查结束。这个场景最有效的排查方式是把页面当成一个完全不看的用户从第一个焦点一直滑到最后一个焦点。建议按下面的顺序检查先查无名控件。所有纯图标按钮、图片操作入口、自定义点击区域确认读屏能回答“这是什么”。再查重复焦点。Button 内部的装饰 Image、卡片里的重复文字有没有被额外聚焦需要整体表达的信息是否适合accessibilityGroup(true)。再查角色和状态。按钮是不是按钮选择项是否使用了合适的标准选择组件禁用是否真的调用了enabled(false)而不是只改变透明度或颜色。检查操作后果。删除、提交、跳转、打开弹窗等操作如果名称本身不足以解释后果再补accessibilityDescription。检查表单。输入框是否能理解字段用途错误、必填、禁用等状态是否仅存在于视觉样式中。最后完整走焦。从页面顶部连续左右滑动观察是否存在焦点遗漏、重复、顺序不自然或必须“猜图标”的地方。华为官方的“提升屏幕朗读无障碍体验”指南本身就把按钮标注、多维信息整体朗读、多 UI 控件组合、禁用屏幕朗读焦点、控件状态变化、内容动态变化和自定义控件走焦顺序等列为独立场景。换句话说无障碍检查不能只盯着一个accessibilityText属性而应该检查整棵交互树。容易理解错的几个地方accessibilityGroup(true)不是“优化朗读”的万能开关。它会让无障碍服务不再分别关注子组件因此包含独立按钮的区域不能随意整体分组。accessibilityLevel(no)和no-hide-descendants也不是一回事。前者针对当前组件后者会把当前组件以及子组件一起从无障碍识别范围中排除。禁用按钮不要只设置.opacity(0.4)。视觉变灰不会自动等价于交互禁用ArkUI 的enabled(false)才会使组件进入不可交互状态。有状态的控件尽量不要全部从Row Image onClick开始手写。Checkbox 已有明确的select状态接口标准组件能够表达业务语义时优先让组件模型承担状态再考虑视觉定制。还有一点很重要本文代码依据官方接口组织但没有在具体 HarmonyOS 工程中替你完成编译和真机读屏验证因此不应把“接口存在”直接等同于“目标设备上的每一句朗读措辞已经验证”。发布前仍应使用项目实际的 API 配置、目标设备和屏幕朗读服务完整走一遍页面。开发经验总结做 ArkUI 页面无障碍补全可以把问题压缩成四个词名称、角色、状态、关系。图标按钮缺的是名称就补accessibilityText操作结果不明确再补accessibilityDescription。多个文本共同表达一条业务信息时再判断是否应该使用accessibilityGroup。装饰性子节点不应该制造额外焦点可以通过无障碍重要性控制。对于勾选、开关、禁用等状态优先使用能够真实表达状态的标准组件和enabled、select等接口而不是只改变颜色。HarmonyOS 7 对应 API 26.0.0本文使用的 ArkUI 通用无障碍属性在 API 26 当前接口中仍然存在Checkbox 等标准组件也继续提供明确的状态接口。真正值得在项目里形成习惯的不是“看到 Image 就加 accessibilityText”而是每做完一个页面都关掉视觉上的先验信息从第一个无障碍焦点走到最后一个它是谁、现在是什么状态、能做什么、操作之后会怎样。只要其中一个问题需要用户猜这个页面就还有继续补充语义的空间。❤️ 如果本文帮到了你…请点个赞让我知道你还在坚持阅读技术长文请收藏本文因为你以后一定还会用上如果你在学习过程中遇到bug请留言我帮你踩坑
阅读完成 · 觉得有帮助?
咨询建站