You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI Charts如何避免自动分组图表无障碍元素

SwiftUI BarMark 图表无障碍分组问题解决方法

使用SwiftUI的BarMark创建图表时,为每个柱形通过.accessibilityLabel和.accessibilityValue自定义了无障碍文本,柱形数量较少时功能正常,但数量增多后,系统会自动将相邻柱形分组,导致无障碍文本混乱。目标是实现类似健康应用活动图表的无障碍行为,让每个柱形都能被独立识别。

原问题代码

var body: some View {
    let salesData: [(Date, Double)] = [
            (Date().addingTimeInterval(-1 * 24 * 60 * 60), 120),
            (Date().addingTimeInterval(-2 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-3 * 24 * 60 * 60), 100),
            (Date().addingTimeInterval(-4 * 24 * 60 * 60), 50),
            (Date().addingTimeInterval(-5 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-6 * 24 * 60 * 60), 140),
            (Date().addingTimeInterval(-7 * 24 * 60 * 60), 130),
            (Date().addingTimeInterval(-8 * 24 * 60 * 60), 180),
            (Date().addingTimeInterval(-9 * 24 * 60 * 60), 50),
            (Date().addingTimeInterval(-10 * 24 * 60 * 60), 80),
            (Date().addingTimeInterval(-11 * 24 * 60 * 60), 80),
            (Date().addingTimeInterval(-12 * 24 * 60 * 60), 100),
            (Date().addingTimeInterval(-13 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-14 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-15 * 24 * 60 * 60), 90),
        ]

    Chart {
        ForEach(salesData, id: \.0) { date, sales in
            BarMark(
                x: .value("Day", date),
                y: .value("Amount", sales)
            ).accessibilityLabel(date.formatted(date: .abbreviated, time: .omitted))
                .accessibilityValue("Amount: \(sales.formatted(.currency(code: "USD")))")
        }
    }
    .accessibilityElement(children: .contain)
    .frame(height: 300)
}

问题现象

开启无障碍功能后,系统自动将两个柱形合并为一个无障碍元素,截图如下:
无障碍检查器截图

目标效果

实现类似健康应用活动图表的无障碍行为,每个柱形独立成为无障碍元素,截图如下:
健康应用截图

解决方案

通过以下两步调整无障碍设置,避免系统自动分组:

  1. 移除图表容器的.accessibilityElement(children: .contain):这个设置会让图表容器将子元素视为一个整体,容易触发系统的自动分组逻辑。
  2. 给每个BarMark添加.accessibilityElement(children: .ignore):强制将每个柱形标记为独立的无障碍元素,告诉系统不要合并它。

修改后的代码

var body: some View {
    let salesData: [(Date, Double)] = [
            (Date().addingTimeInterval(-1 * 24 * 60 * 60), 120),
            (Date().addingTimeInterval(-2 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-3 * 24 * 60 * 60), 100),
            (Date().addingTimeInterval(-4 * 24 * 60 * 60), 50),
            (Date().addingTimeInterval(-5 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-6 * 24 * 60 * 60), 140),
            (Date().addingTimeInterval(-7 * 24 * 60 * 60), 130),
            (Date().addingTimeInterval(-8 * 24 * 60 * 60), 180),
            (Date().addingTimeInterval(-9 * 24 * 60 * 60), 50),
            (Date().addingTimeInterval(-10 * 24 * 60 * 60), 80),
            (Date().addingTimeInterval(-11 * 24 * 60 * 60), 80),
            (Date().addingTimeInterval(-12 * 24 * 60 * 60), 100),
            (Date().addingTimeInterval(-13 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-14 * 24 * 60 * 60), 150),
            (Date().addingTimeInterval(-15 * 24 * 60 * 60), 90),
        ]

    Chart {
        ForEach(salesData, id: \.0) { date, sales in
            BarMark(
                x: .value("Day", date),
                y: .value("Amount", sales)
            )
            .accessibilityElement(children: .ignore)
            .accessibilityLabel(date.formatted(date: .abbreviated, time: .omitted))
            .accessibilityValue("金额:\(sales.formatted(.currency(code: "USD")))")
        }
    }
    .chartAccessibilityLabel("销售数据图表") // 可选:添加图表总标签,和健康应用逻辑一致
    .frame(height: 300)
}

原理说明

当元素在视觉上过于密集时,VoiceOver会自动合并相邻的相似元素以减少交互次数。通过给每个BarMark设置.accessibilityElement(children: .ignore),可以明确告诉系统该元素是一个独立的无障碍单元,需要单独识别。同时移除图表层面的容器无障碍设置,避免干扰子元素的无障碍识别逻辑。

内容的提问来源于stack exchange,提问作者Huy Vu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 06:17:13