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) }
问题现象
开启无障碍功能后,系统自动将两个柱形合并为一个无障碍元素,截图如下:
目标效果
实现类似健康应用活动图表的无障碍行为,每个柱形独立成为无障碍元素,截图如下:
解决方案
通过以下两步调整无障碍设置,避免系统自动分组:
- 移除图表容器的
.accessibilityElement(children: .contain):这个设置会让图表容器将子元素视为一个整体,容易触发系统的自动分组逻辑。 - 给每个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
相关产品推荐
相关产品推荐

