前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SwiftUI中的水平条形图

SwiftUI中的水平条形图

作者头像
韦弦zhy
发布2022-11-07 16:28:38
4.7K0
发布2022-11-07 16:28:38
举报

SwiftUI中的水平条形图

水平条形图以矩形条的形式呈现数据类别,其宽度与它们所代表的数值成正比。本文展示了如何在垂直条形图的基础上创建一个水平柱状图。

水平条形图不是简单的垂直条形图的旋转。在Numbers 等应用程序中,水平条形图被定义为独立的图表类型,而不是垂直条形图。除了条形差异外,x轴和y轴的格式也需要不同。

相关文章
  1. How to create a Bar Chart in SwiftUI
  2. Add Axes to a Bar Chart in SwiftUI
  3. Hide Bar Chart Axes in SwiftUI
  4. Bar Chart with multiple data sets in SwiftUI
  5. SwiftUI 中的水平条形图

将条形图转换为水平

水平条形图不仅仅是在垂直条形图上的配置,有一些元素是可以重复使用的。对于垂直条形图组件和水平条形图组件来说,重复使用一些结构和SwiftUI视图并不简单。标题和关键区域可以原样重用。创建BarChartView的副本,并将其名称改为BarChartHView。它控制了图表的布局,其中的三个视图被改为YaxisHViewChartAreaHViewXaxisHView,它们最初只是垂直条形图中使用的视图的副本。maxTickHeight被改为maxTickWidth,因为它现在取决于可用的水平空间。

代码语言:javascript
复制
struct BarChartHView: View {
    var title: String
    var chartData: BarChartData
    var isShowingYAxis = true
    var isShowingXAxis = true
    var isShowingHeading = true
    var isShowingKey = true

    var body: some View {
        let data = chartData.data
        GeometryReader { gr in
            let axisWidth = gr.size.width * (isShowingYAxis ? 0.15 : 0.0)
            let axisHeight = gr.size.height * (isShowingXAxis ? 0.1 : 0.0)
            let keyHeight = gr.size.height * (isShowingKey ? 0.1 : 0.0)
            let headHeight = gr.size.height * (isShowingHeading ? 0.14 : 0.0)
            let fullChartHeight = gr.size.height - axisHeight - headHeight - keyHeight
            let fullChartWidth = gr.size.width - axisWidth
            
            let maxValue = data.flatMap { $0.values }.max()!
            let tickMarks = AxisParameters.getTicks(top: Int(maxValue))
            let maxTickWidth = fullChartWidth * 0.95
            let scaleFactor = maxTickWidth / CGFloat(tickMarks[tickMarks.count-1])
            
            VStack(spacing:0) {
                if isShowingHeading {
                    ChartHeaderView(title: title)
                        .frame(height: headHeight)
                }
                ZStack {
                    Rectangle()
                        .fill(Color(#colorLiteral(red: 0.8906477705, green: 0.9005050659, blue: 0.8208766097, alpha: 1)))
                    
                    VStack(spacing:0) {
                        if isShowingKey {
                            KeyView(keys: chartData.keys)
                                .frame(height: keyHeight)
                        }
                        
                        HStack(spacing:0) {
                            if isShowingYAxis {
                                YaxisHView(ticks: tickMarks, scaleFactor: Double(scaleFactor))
                                    .frame(width:axisWidth, height: fullChartHeight)
                            }
                            ChartAreaHView(data: data, scaleFactor: Double(scaleFactor))
                                .frame(height: fullChartHeight)
                        }
                        HStack(spacing:0) {
                            Rectangle()
                                .fill(Color.clear)
                                .frame(width:axisWidth, height:axisHeight)
                            if isShowingXAxis {
                                XaxisHView(data: data)
                                    .frame(height:axisHeight)
                            }
                        }
                    }
                }
            }
        }
    }
}

ChartAreaHViewChartAreaView几乎相同,只是Bars被放置在一个垂直的堆栈中,而不是水平的堆栈。

代码语言:javascript
复制
struct ChartAreaHView: View {
    var data: [DataItem]
    var scaleFactor: Double
    
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 5.0)
                .fill(Color(#colorLiteral(red: 0.8906477705, green: 0.9005050659, blue: 0.8208766097, alpha: 1)))
            
            VStack {
                VStack(spacing:0) {
                    ForEach(data) { item in
                        BarHView(
                            name: item.name,
                            values: item.values,
                            scaleFactor: scaleFactor)
                    }
                }
            }
        }
    }
}

BarHView是由原来的BarView改变的,以水平方式布局条形。矩形条的宽度与数据的值成正比。

代码语言:javascript
复制
struct BarHView: View {
    var name: String
    var values: [Double]
    var scaleFactor: Double
    
    var body: some View {
        GeometryReader { gr in
            let padHeight = gr.size.height * 0.07
            VStack(spacing:0) {
                Spacer()
                    .frame(height:padHeight)
                
                ForEach(values.indices) { i in
                    let barSize = values[i] * scaleFactor
                    
                    ZStack {
                        HStack(spacing:0) {
                            Rectangle()
                                .fill(ChartColors.BarColor(i))
                                .frame(width: min(5.0, CGFloat(barSize)), alignment: .trailing)
                            Spacer()
                        }
                        
                        HStack(spacing:0) {
                            RoundedRectangle(cornerRadius:5.0)
                                .fill(ChartColors.BarColor(i))
                                .frame(width: CGFloat(barSize), alignment: .trailing)
                                .overlay(
                                    Text("\(values[i], specifier: "%.0F")")
                                        .font(.footnote)
                                        .foregroundColor(.white)
                                        .fontWeight(.bold)
                                        .offset(x:-10, y:0)
                                    ,
                                    alignment: .trailing
                                )
                            Spacer()
                        }
                    }
                }

                Spacer()
                    .frame(height:padHeight)
            }
        }
    }
}

将条形图改为水平布局

更新Y轴

我们创建了一个YaxisHView视图,用于在水平条形图上显示Y轴和条形图中的数据类别。Y轴标签的Swift代码与垂直条形图的X轴代码相似,宽度设置与高度设置互换。两种图表类型的y轴线的代码都是一样的。

代码语言:javascript
复制
struct YaxisHView: View {
    var data: [DataItem]
    
    var body: some View {
        GeometryReader { gr in
            let labelHeight = (gr.size.height * 0.9) / CGFloat(data.count)
            let padHeight = gr.size.height * 0.05 / CGFloat(data.count)
            
            ZStack {
                Rectangle()
                    .fill(Color(#colorLiteral(red: 0.8906477705, green: 0.9005050659, blue: 0.8208766097, alpha: 1)))
                
                // y-axis line
                Rectangle()
                    .fill(Color.black)
                    .frame(width:1.5)
                    .offset(x: (gr.size.width/2.0)-1, y: 1)
                
                VStack(spacing:0) {
                    ForEach(data) { item in
                        Text(item.name)
                            .font(.footnote)
                            .frame(height: labelHeight)
                    }
                    .padding(.vertical, padHeight)
                }
            }
        }
    }
}

y轴显示水平条形图上的数据类别

更新X轴

同样,创建了一个XaxisHView视图来显示水平条形图的X轴,并使用与垂直条形图的Y轴类似的代码来布置刻度线和刻度值。

代码语言:javascript
复制
struct XaxisHView: View {
    var ticks: [Int]
    var scaleFactor: Double
    
    var body: some View {
        GeometryReader { gr in
            let fullChartWidth = gr.size.width
            ZStack {
                // x-axis line
                Rectangle()
                    .fill(Color.black)
                    .frame(height: 1.5)
                    .offset(x: 0, y: -(gr.size.height/2.0))
                
                // Tick marks
                ForEach(ticks, id:\.self) { t in
                    VStack {
                        Rectangle()
                            .frame(width: 1, height: 10)
                        Text("\(t)")
                            .font(.footnote)
                            .rotationEffect(Angle(degrees: -45))
                        Spacer()
                    }
                    .offset(x:  (CGFloat(t) * CGFloat(scaleFactor)) - (fullChartWidth/2.0) - 1)
                }
            }
        }
    }
}

X轴显示水平条形图上的比例和数值

水平和垂直条形图

一个iPad模拟器被用来比较垂直和水平条形图的使用,以显示2018年五岁以下儿童死亡率最高的国家。柱状图的多数据功能被用来比较男孩和女孩的死亡率。

2018年最高的5岁以下儿童死亡率显示在垂直和水平条形图中

水平条形图重用了垂直条形图的很多代码,所以显示或隐藏标题、键和轴的效果是有效的。在水平条形图中,显示条形图上的数值并隐藏X轴可以使图表更简洁。

显示和隐藏水平条形图上的元素

结论

创建水平条形图的SwiftUI代码与创建垂直条形图的代码不同。在创建垂直条形图时学到的技术可以重复使用,但最好将水平条形图视为与垂直条形图不同的图表。当我们深入到轴等组件时,可以看到两个图表中的轴线都是一样的,但是它们的标签和定位在x和y之间是换位的。这可能是将这些组件分解成更小的SwiftUI视图并通过组合来重用的原因。

gist file for Horizontal bar chart SwiftUI code

Horizontal Bar Chart in SwiftUI https://swdevnotes.com/swift/2021/horizontal-bar-chart-in-swiftui/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 将条形图转换为水平
  • 更新Y轴
  • 更新X轴
  • 水平和垂直条形图
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档