上一篇咱们讲了 accessibilityGroup 把多个组件聚合成一个焦点。但实际开发中,信息往往是多维的、有层级结构的——卡片里套卡片,分组里再分组。这时候光会"聚合"还不够,还得会处理嵌套组里的重复朗读问题。这篇就聊这个更进阶的场景。

一、什么情况会出现"嵌套组"

先定义一下场景。所谓"嵌套组",就是一个已经做了聚合的语义单元里,还包含着可以独立获焦的子对象。典型例子是天气卡片:

  • 外层:一张天气卡片,包含"时间 + 地点"这一组信息
  • 内层:时间"12:05"是一个焦点候选,地点"北京"是另一个焦点候选

如果处理不当,用户滑动到这张卡片时,会先听到一次"时间组 12:05 北京"(外层聚合的整体朗读),再继续滑动,又听到"12:05",再滑一下,又听到"北京"——同一个信息被播报了两遍

这就是多维信息场景的核心问题:层级结构带来的重复朗读

二、官方给出的原则

官方文档针对这个场景的原则很明确:

应避免两个可获焦对象的功能或朗读内容产生重复。

翻译过来就是:如果某个信息的完整描述,已经在一个父控件的整体朗读里覆盖了,那就不应该再让子控件独立获焦、重复播报。对同一个信息结构的完整描述,应该统一标注在父控件上,子控件不再单独获焦。

这个原则和上一篇"聚合边界 = 语义边界"一脉相承,只是它特别针对有嵌套层级的情况,防止你聚了一层却漏了另一层。

三、错误写法:父控件和子控件都在读

看一个典型的错误示范。下面这个 Row 既设了父级的无障碍文本,子控件又各自保留了独立朗读能力:

Row(){
  Text('12:05')        // 时间,可独立聚焦
    .fontSize(32)
    .fontColor(Color.Red)
    .fontWeight(FontWeight.Bold)

  Text('Beijing')      // 地点,可独立聚焦
    .fontSize(20)
    .fontColor(Color.Green)
    .fontWeight(FontWeight.Bold)
}
.accessibilityText('Time Group')  // 父级也设了文本
.height(50)

这把雷全踩了:

  1. 父级 Row 通过 accessibilityText('Time Group') 提供了一个朗读入口
  2. 子控件"12:05"和"Beijing"依然可以独立获焦、独立朗读

结果就是:焦点落在父级时读"Time Group 12:05 Beijing",继续滑到子控件又读"12:05"、再读"Beijing"。官方注释直接点明这是"不正确的"——信息重复了两次。

四、正确写法:父级统一描述,子级禁止单独获焦

正确做法是把这个信息结构在父级完整标注,然后让子控件不再单独获焦:

Row(){
  Text('07:05')        // 不再独立聚焦
    .fontSize(32)
    .fontColor(Color.Red)
    .fontWeight(FontWeight.Bold)

  Text('Moscow')       // 不再独立聚焦
    .fontSize(20)
    .fontColor(Color.Green)
    .fontWeight(FontWeight.Bold)
}
.height(50)
.accessibilityGroup(true)   // 整组一个焦点,读 "07:05 Moscow"

注意,这里用的是 accessibilityGroup(true),而不是 accessibilityText。区别很关键:

  • accessibilityGroup(true)阻止子控件独立获焦,同时把子控件的内容整合进整体朗读,读出来是"07:05 Moscow"
  • 光设 accessibilityText 不会阻止子控件获焦,反而会和子控件的朗读重复

这就是上一篇错误示范里注解说"子组件无法聚焦、无法朗读"的原因——accessibilityGroup 才是真正"收口"的那个属性,accessibilityText 只是"附加一段朗读内容"。

五、多维信息处理的三个层次

把多维信息的处理策略分层,会清晰很多:

层次一:扁平信息聚合

最简单的场景,多个平级组件描述同一个对象。直接用 accessibilityGroup(true) 把整组打包,一次读完整信息。上一篇天气卡片的例子就属于这层。

层次二:嵌套信息的收口

有层级结构时,父级做统一标注,子级禁止独立获焦。确保"每一个语义单元只有一个朗读入口",消灭重复播报。

层次三:可操作元素的保留

如果嵌套结构里有些元素是用户需要独立操作的(比如卡片里的收藏按钮),那就不能简单地把全部子控件都吞进父组。这种情况下,可操作元素要跳出父组聚合范围,保持独立焦点,只把纯展示信息聚合。

六、一个实操建议:先画语义树

处理多维信息时,一个很有效的方法是先在纸面上画"语义树",把界面信息拆成层级:

天气卡片(一个语义单元)
├── 时间:12:05
└── 地点:北京

然后自问一个问题:视障用户理解这条信息,需要几步朗读?

答案如果是一个焦点、一次朗读就能说清楚,那就应该聚合到根节点,子节点全部收口。如果需要分步骤(比如先选城市、再看天气、再操作某个按钮),才保留多个焦点。

这个"一步还是多步"的判断,比任何技术细节都更本质。

七、总结一下下

多维信息整体朗读,本质是解决"重复"——重复的焦点、重复的朗读、重复的操作。核心原则一句话:同一个信息结构,只保留一个朗读入口。

实操上就三条:

  1. 扁平信息用 accessibilityGroup(true) 聚合
  2. 嵌套信息父级标注、子级收口,用 accessibilityGroup 而非 accessibilityText
  3. 需要独立操作的元素保留独立焦点,不参与聚合

下一篇转向另一个维度——焦点已经聚合好了,但焦点位置可能会因为控件消失、页面跳转而"跑丢",这时该怎么主动管理焦点。

Logo

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

更多推荐