SwiftUI图表中点击BarMark时如何修改其颜色
SwiftUI Charts 实现点击BarMark修改样式
因为BarMark本身没有直接的.onTap修饰符,我们可以通过Chart的手势结合状态变量来实现点击修改样式的需求,核心思路是用状态记录选中的条形项,再根据状态动态调整BarMark的样式。
完整实现步骤
- 先定义数据模型(可根据实际业务调整):
import SwiftUI import Charts struct DataItem: Identifiable { let id = UUID() let day: Date let duration: Double } // 模拟近1小时的数据 extension [DataItem] { static let lastOneHour: [DataItem] = { let now = Date() return (0..<6).map { hourOffset in DataItem(day: now.addingTimeInterval(-TimeInterval(hourOffset)*3600), duration: Double.random(in: 10...50)) } }() }
- 实现可点击的条形图:
struct TapableBarChart: View { // 记录选中的条形项 @State private var selectedItem: DataItem? var body: some View { Chart { ForEach(DataItem.lastOneHour) { item in BarMark( x: .value("Hour", item.day, unit: .hour), y: .value("Duration", item.duration) ) // 根据选中状态切换样式 .foregroundStyle(selectedItem?.id == item.id ? .orange : .blue) .opacity(selectedItem?.id == item.id ? 0.8 : 1.0) .cornerRadius(selectedItem?.id == item.id ? 8 : 4) .border(selectedItem?.id == item.id ? .red : .clear, width: 2) } } .onTapGesture { location in let chartProxy = ChartProxy(self) guard let plotArea = chartProxy.plotAreaFrame else { return } // 计算点击位置在图表绘图区域的相对坐标 let relativeX = (location.x - plotArea.minX) / plotArea.width let relativeY = (location.y - plotArea.minY) / plotArea.height // 将相对坐标转换为图表的X轴值(这里是Date类型) if let tappedHour = chartProxy.value(atX: relativeX, as: Date.self), // 匹配对应的DataItem(按小时粒度匹配) let matchedItem = DataItem.lastOneHour.first(where: { Calendar.current.isDate($0.day, equalTo: tappedHour, toGranularity: .hour) }) { // 点击已选中的项则取消选中,否则切换选中项 selectedItem = matchedItem == selectedItem ? nil : matchedItem } } } }
关键说明
- 状态变量:用
@State private var selectedItem跟踪当前选中的条形,驱动样式变化 - 样式动态调整:通过
foregroundStyle、opacity、cornerRadius、border等修饰符,根据选中状态修改BarMark的外观 - 点击识别:借助
ChartProxy获取点击位置对应的图表数据,通过坐标转换匹配到对应的DataItem,更新选中状态
你可以根据需求自定义更多样式变化,比如修改填充图案、阴影效果等。
内容的提问来源于stack exchange,提问作者Leela
相关产品推荐
相关产品推荐

