如何使用SwiftUI和Swift Charts实现单数据集柱状图独立展示
问题描述
我正尝试通过SwiftUI和Swift Charts,基于自定义模型创建柱状图,要求每个视图仅展示模型示例数据中的单个数据集。
模型代码
import Foundation struct VerticalBarChart: Identifiable, Hashable { let id: UUID var image: String var title: String var xValue: [String] var yValue: [Int] var dateCreated: Date } extension VerticalBarChart { static var sampleData: [VerticalBarChart] { [ VerticalBarChart( id: UUID(), image: "chart.bar", title: "Vertical Bar Chart 1", xValue: ["Monday", "Tuesday", "Wednesday", "Thursday", "friday"], yValue: [500, 600, 700, 800, 900, 1000], dateCreated: Date.now), VerticalBarChart( id: UUID(), image: "chart.bar", title: "Vertical Bar Chart 2", xValue: ["Week 1", "Week 2", "Week 3", "Week 3"], yValue: [1, 2, 3, 4], dateCreated: Date.now), VerticalBarChart( id: UUID(), image: "chart.bar", title: "Vertical Bar Chart 3", xValue: ["Wednesday"], yValue: [700], dateCreated: Date.now) ] } }
当前视图代码
import SwiftUI import Charts struct VerticalBarChartView: View { var verticalBarChart: VerticalBarChart var body: some View { VStack { Chart { ForEach(VerticalBarChart.sampleData) { element in BarMark( x: .value("x-axis", element.xValue), y: .value("y-axis", element.yValue) ) } } } } }
需求:让每个视图仅展示单个数据集(一组xValue和yValue)对应的柱状图,从示例数据生成三个独立视图分别展示三个图表。
解决方案
当前代码存在两个核心问题:一是视图直接遍历所有示例数据,未使用传入的单个数据集实例;二是BarMark无法直接接收数组类型的x/y参数,需要将两组数据一一配对后遍历。
1. 修正VerticalBarChartView,展示单个数据集
通过zip将x和y值配对,再用enumerated()生成可识别的元素(元组不遵循Identifiable协议),为每个配对生成对应的柱状条:
import SwiftUI import Charts struct VerticalBarChartView: View { var verticalBarChart: VerticalBarChart var body: some View { VStack { // 显示图表标题 Text(verticalBarChart.title) .font(.title) .padding(.bottom) Chart { // 遍历当前实例的x/y值对 ForEach(Array(zip(verticalBarChart.xValue, verticalBarChart.yValue)).enumerated(), id: \.offset) { _, pair in BarMark( x: .value("分类", pair.0), y: .value("数值", pair.1) ) } } .padding() } } }
2. 创建父视图生成三个独立图表
遍历示例数据集合,为每个数据实例生成单独的VerticalBarChartView:
struct ChartContainerView: View { var body: some View { ScrollView { VStack(spacing: 30) { ForEach(VerticalBarChart.sampleData) { chartData in VerticalBarChartView(verticalBarChart: chartData) .frame(height: 300) .background(Color.gray.opacity(0.1)) .cornerRadius(10) } } .padding() } } } // 预览视图 struct ChartContainerView_Previews: PreviewProvider { static var previews: some View { ChartContainerView() } }
额外提示
- 第一个示例数据中
xValue有5个元素,yValue有6个,zip会取较短数组的长度,最终生成5个柱状条,建议保持两组数据的长度一致; - 可以给模型添加计算属性优化配对逻辑:
extension VerticalBarChart { var dataPairs: [(x: String, y: Int)] { Array(zip(xValue, yValue)) } }
之后在视图中直接遍历verticalBarChart.dataPairs.enumerated()即可。
内容的提问来源于stack exchange,提问作者Tony Staunton
相关产品推荐
相关产品推荐

