如何用SwiftUI原生Charts库实现单月多数据柱状图
解决方案
1. 修复Identifiable协议错误
报错[OrdersHistory] must conform to Identifiable是因为SwiftUI原生Chart组件需要数据源中的元素能被唯一标识,最简单的解决方式是让OrdersHistory结构体遵循Identifiable协议,添加自动生成的唯一ID:
import Foundation struct OrdersHistory: Identifiable { // 自动生成唯一ID,满足Identifiable协议要求 let id = UUID() let date: Date let completed: Int let cancelled: Int let pending: Int }
如果不想修改结构体,也可以在初始化Chart时显式指定标识字段(比如用date作为唯一标识):
Chart(ordersData, id: \.date) { /* ... */ }
2. 实现单月三组数据的柱状图
将原UIKit的ViewController逻辑迁移为SwiftUI视图,使用原生Chart组件创建分组柱状图(每个日期对应3组数据的柱子):
SwiftUI图表视图代码
import SwiftUI import Charts struct OrdersChartView: View { let ordersData: [OrdersHistory] // 格式化日期为当月的日(如1-31) private func formatDay(_ date: Date) -> String { let formatter = DateFormatter() formatter.dateFormat = "d" return formatter.string(from: date) } var body: some View { Chart(ordersData) { order in // 已完成订单柱状条 BarMark( x: .value("日期", formatDay(order.date)), y: .value("已完成", order.completed) ) .foregroundStyle(.green) // 已取消订单柱状条 BarMark( x: .value("日期", formatDay(order.date)), y: .value("已取消", order.cancelled) ) .foregroundStyle(.red) // 待处理订单柱状条 BarMark( x: .value("日期", formatDay(order.date)), y: .value("待处理", order.pending) ) .foregroundStyle(.orange) } .chartXAxisLabel("日期") .chartYAxisLabel("订单数量") .chartLegend(position: .bottom) // 图例放在底部 .padding() } }
在UIKit中嵌入SwiftUI图表
如果需要保留原ViewController(UIKit环境),可以通过UIHostingController嵌入SwiftUI视图:
import UIKit import SwiftUI class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 生成测试数据(替换为你的真实数据) let sampleData: [OrdersHistory] = [ OrdersHistory(date: Calendar.current.date(from: DateComponents(year: 2024, month: 5, day: 1))!, completed: 5, cancelled: 2, pending: 3), OrdersHistory(date: Calendar.current.date(from: DateComponents(year: 2024, month: 5, day: 2))!, completed: 7, cancelled: 1, pending: 2), OrdersHistory(date: Calendar.current.date(from: DateComponents(year: 2024, month: 5, day: 3))!, completed: 3, cancelled: 4, pending: 1), // 可继续添加当月其他日期的数据 ] // 嵌入SwiftUI图表视图 let chartView = OrdersChartView(ordersData: sampleData) let hostingController = UIHostingController(rootView: chartView) addChild(hostingController) hostingController.view.frame = view.bounds view.addSubview(hostingController.view) hostingController.didMove(toParent: self) } }
3. 可选:堆叠柱状图
如果需要将三组数据堆叠显示(而非分组),只需给每个BarMark添加stacking(.value)修饰符:
BarMark(/* ... */) .foregroundStyle(.green) .stacking(.value)
内容的提问来源于stack exchange,提问作者J_A_F_Casillas
相关产品推荐
相关产品推荐

