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

iOS 15 SwiftUI堆叠条形图实现及左侧数据显示问题

修复SwiftUI堆叠条形图并添加左侧数据显示

原代码问题分析

  • 用VStack放置分段导致条形分散,无法实现垂直堆叠效果
  • HStack内的Spacer使用不当,造成条形间距混乱
  • 未处理堆叠偏移计算,分段未按高度叠加排列

修改后的完整代码

struct StackedBarChartView: View {
    let dataPoints: [String]
    let dataSets: [[Int]] // 子数组对应单个条形的分段数据
    let colors: [Color]
    let fixedWidth: CGFloat
    
    // 计算单个条形的总数值,用于换算高度占比
    private func totalValue(for barIndex: Int) -> CGFloat {
        CGFloat(dataSets[barIndex].reduce(0, +))
    }
    
    var body: some View {
        HStack(alignment: .bottom, spacing: 20) {
            // 左侧数据刻度标签
            VStack(alignment: .trailing, spacing: 0) {
                let allValues = dataSets.flatMap { $0 }
                let maxTotal = allValues.reduce(0, +)
                
                // 按步长生成刻度,可自行调整step值
                ForEach(0...maxTotal step: 10) { value in
                    Text("\(value)")
                        .font(.caption)
                        .frame(height: 300 / CGFloat(maxTotal) * 10)
                }
            }
            
            // 图表主体区域
            VStack(alignment: .center) {
                // 横向排列所有堆叠条形
                HStack(alignment: .bottom, spacing: 15) {
                    ForEach(dataSets.indices, id: \.self) { barIndex in
                        let total = totalValue(for: barIndex)
                        
                        ZStack(alignment: .bottom) {
                            // 可选:条形背景占位,显示完整高度范围
                            RoundedRectangle(cornerRadius: 15)
                                .fill(Color.gray.opacity(0.1))
                                .frame(width: fixedWidth, height: 300)
                            
                            // 堆叠的分段条形
                            VStack(spacing: 0) {
                                ForEach(dataSets[barIndex].indices, id: \.self) { segmentIndex in
                                    let value = dataSets[barIndex][segmentIndex]
                                    let segmentHeight = CGFloat(value) / total * 300
                                    
                                    RoundedRectangle(cornerRadius: 15)
                                        .fill(colors[segmentIndex % colors.count])
                                        .frame(width: fixedWidth, height: segmentHeight)
                                        .overlay(
                                            // 可选:在分段内显示数值
                                            Text("\(value)")
                                                .font(.system(size: 10))
                                                .foregroundColor(.white)
                                        )
                                }
                            }
                        }
                    }
                }
                
                // 底部分类标签
                HStack(spacing: 15) {
                    ForEach(dataPoints, id: \.self) { point in
                        Text(point)
                            .font(.caption)
                    }
                }
                .padding(.top, 8)
            }
        }
        .padding()
        .frame(height: 350)
        .animation(.easeInOut, value: dataSets)
    }
}

struct ContentView: View {
    let dataPoints = ["A", "B", "C", "D"]
    let dataSets = [[20, 30, 40, 10], [10, 20, 30, 40], [5, 15, 10, 30]]
    let colors: [Color] = [.red, .green, .blue, .orange]

    var body: some View {
        StackedBarChartView(dataPoints: dataPoints, dataSets: dataSets, colors: colors, fixedWidth: 40)
    }
}

关键修改说明

  1. 堆叠逻辑修复:
    • 用VStack(spacing: 0)替代分散布局,让分段垂直紧密堆叠
    • 基于条形总数值计算分段高度占比,确保所有堆叠后总高度一致
  2. 左侧数据显示:
    • 添加左侧VStack作为刻度标签区,按总最大值比例分配刻度高度
    • 可按需调整刻度步长,或改为显示每个分段的具体数值
  3. 布局优化:
    • 用HStack(alignment: .bottom)确保所有条形底部对齐
    • 增加背景占位条,清晰展示条形高度范围
    • 调整条形宽度和间距,提升视觉舒适度
  4. iOS15适配:
    • 将动画绑定到dataSets,避免iOS15下动画异常
    • 固定条形宽度,适配不同屏幕尺寸

内容的提问来源于stack exchange,提问作者Muju

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 01:12:12