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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:23:13