一、图表布局

  • 条形(柱状)图以矩形条的形式呈现数据的类别,其宽度和高度与它们表示的值成比例。SwiftUI 对探索不同布局和预览实时视图结果是很友好的,很容易将部分内容提取到子视图中,以便每个部分都很小且易于维护。
  • 从包含 HistogramView 以及可能的其它文本或数据的视图开始,HistogramView 包含一个标题和一个图表区,它们由文本和圆角矩形表示。
  • HistogramView 的创建:
struct HistogramView: View {var title: Stringvar body: some View {GeometryReader { gr inlet headHeight = gr.size.height * 0.10VStack {HistogramHeaderView(title: title, height: headHeight)HistogramAreaView()}}}
}struct HistogramHeaderView: View {var title: Stringvar height: CGFloatvar body: some View {Text(title).frame(height: height)}
}struct HistogramAreaView: View {var body: some View {ZStack {RoundedRectangle(cornerRadius: 5.0).fill(Color(#colorLiteral(red: 0.80, green: 0.90, blue: 0.80, alpha: 1)))}}
}
  • 在 ContentView 中调用 HistogramView:
struct ContentView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}struct ContentView: View {var body: some View {VStack {Text("数据分析").font(.title)HistogramView(title: "柱状图").frame(width: 300, height: 300, alignment: .center)Spacer()}.padding()}
}
  • 效果如下所示:

二、添加条形(柱状)图

  • 定义一些简单的数据类别,如一周内每天看手机的时间分钟数,以下表数据被作为主视图的项目数据,每一条数据包含一个键值对(名称和值)。在平常的 App 里,这些数据应该通过 ViewModel 从 model 里取数据:
Day Times
星期一 188
星期二 209
星期三 300
星期四 150
星期五 198
星期六 488
星期日 409
  • 修改图表区并设置数据:
struct ContentView: View {let chartData: [DataItem] = [DataItem(name: "星期一", value: 188),DataItem(name: "星期二", value: 209),DataItem(name: "星期三", value: 300),DataItem(name: "星期四", value: 150),DataItem(name: "星期五", value: 198),DataItem(name: "星期六", value: 488),DataItem(name: "星期日", value: 409)]var body: some View {VStack {Text("屏幕使用时间").font(.title)HistogramView(title: "一周数据分析", data: chartData).frame(width: 350, height: 500, alignment: .center)Spacer()}}
}
  • 更新 HistogramView 使数据可以作为参数传递到 HistogramAreaView:
struct HistogramView: View {var title: Stringvar data: [DataItem]var body: some View {GeometryReader { gr inlet headHeight = gr.size.height * 0.10VStack {HistogramHeaderView(title: title, height: headHeight)HistogramAreaView(data: data)}}}
}
  • 更新后的 HistogramView 需要一个 DataItem 的列表,GeometryReader 被用来确定条形图的可用高度,数据中的最大值得到后并传递给每个 ColumnView,主图表区域保持原来的圆角矩形,并以水平堆叠的方式叠加一系列条形,每个 DataItem 对应一个条形:
struct HistogramAreaView: View {var data: [DataItem]var body: some View {GeometryReader { gr inlet fullBarHeight = gr.size.height * 0.90let maxValue = data.map { $0.value }.max()!ZStack {RoundedRectangle(cornerRadius: 5.0).fill(Color(#colorLiteral(red: 0.80, green: 0.90, blue: 0.80, alpha: 1)))VStack {HStack(spacing:0) {ForEach(data) { item inColumnView(name: item.name,value: item.value,maxValue: maxValue,fullBarHeight: Double(fullBarHeight))}}.padding(4)}}}}
}
  • 为 ColumnView 创建一个新的视图,该视图为每条数据创建一个条形图,它需要每一条数据的名称和值以及最大值和可用的条形高度,每个条形图都表示为圆角矩形,条形高度相对于最大条形高度设置,条形的颜色设置为红色:
struct ColumnView: View {var name: Stringvar value: Doublevar maxValue: Doublevar fullBarHeight: Doublevar body: some View {let barHeight = (Double(fullBarHeight) / maxValue) * valueVStack {Spacer()ZStack {VStack {Spacer()RoundedRectangle(cornerRadius:5.0).fill(Color.red).frame(height: CGFloat(barHeight), alignment: .trailing)}VStack {Spacer()Text("\(value, specifier: "%.0F")").font(.footnote).foregroundColor(.white).fontWeight(.bold)}}Text(name).font(Font.system(size: 13))}.padding(.horizontal, 4)}
}
  • 最终效果如下:

三、横屏显示(屏幕旋转)

  • 条形(柱状)图在使用样本数据时看起来不错,图表会调整到适合它所处的容器视图之中。同样的图表可以放到任何没有其他视图的新视图上,当设备旋转时,图标将会充满空间并调整大小:
struct ContentView: View {let chartData: [DataItem] = [DataItem(name: "星期一", value: 188),DataItem(name: "星期二", value: 209),DataItem(name: "星期三", value: 300),DataItem(name: "星期四", value: 150),DataItem(name: "星期五", value: 198),DataItem(name: "星期六", value: 488),DataItem(name: "星期日", value: 409)]var body: some View {VStack() {Text("屏幕使用时间").font(.title)HistogramView(title: "一周数据分析", data: chartData)Spacer()}.padding()}
}
  • 效果如下:

四、王者荣耀英雄胜率的柱状图渲染分析

  • 王者荣耀里面有很多的英雄,根据版本的不同英雄的胜率也会有所不同,肯定有很多小伙伴儿好奇哪些英雄的胜率高,哪些英雄的胜率低? 现在我们就用条形图的形式来清晰的展示出 2022 王者荣耀英雄胜率排行。
  • 2022 王者荣耀的打野路英雄的最新胜率,如下所示:
位置 热度 英雄 胜率
打野 T0 孙悟空 49.40%
打野 T1 李信 50.68%
打野 T1 亚瑟 48.41%
打野 T1 典韦 52.40%
打野 T1 48.24%
打野 T1 李元芳 49.53%
打野 T1 48.76%
打野 T2 兰陵王 47.08%
打野 T2 韩信 50.94%
打野 T2 赵云 50.34%
打野 T2 程咬金 50.47%
打野 T2 51.80%
打野 T2 李白 50.49%
打野 T2 阿珂 50.77%
打野 T2 钟无艳 50.68%
打野 T2 宫本武藏 49.17%
打野 T3 芈月 50.17%
打野 T3 刘备 52.85%
打野 T3 娜可露露 48.39%
打野 T3 橘右京 49.69%
打野 T3 云樱 49.66%
打野 T3 47.00%
打野 T3 司马懿 52.20%
打野 T3 露娜 49.88%
打野 T3 猪八戒 48.41%
打野 T3 阿骨朵 54.28%
打野 T3 49.67%
打野 T3 达摩 49.85%
打野 T3 杨戬 52.44%
打野 T3 百里玄策 51.75%
打野 T3 曹操 48.91%
打野 T3 雅典娜 56.35%
打野 T3 裴擒虎 47.92%
打野 T3 云中君 50.68%
打野 T3 盘古 48.66%
  • 使用英雄名在条形图中绘制:
struct DataItem: Identifiable {let name: Stringlet value: Doublelet id = UUID()
}struct ContentView: View {let chartData: [DataItem] = [DataItem(name: "孙悟空", value: 49.40),DataItem(name: "李信", value: 50.68),DataItem(name: "亚瑟", value: 48.41),DataItem(name: "典韦", value: 52.40),DataItem(name: "凯", value: 48.24),DataItem(name: "李元芳", value: 49.53),DataItem(name: "澜", value: 48.76),DataItem(name: "兰陵王", value: 47.08),DataItem(name: "韩信", value: 50.94),DataItem(name: "赵云", value: 50.34),DataItem(name: "程咬金", value: 50.47),DataItem(name: "曜", value: 51.80),DataItem(name: "李白", value: 50.49),DataItem(name: "阿珂", value: 50.77),DataItem(name: "钟无艳", value: 50.68),DataItem(name: "宫本武藏", value: 49.17),DataItem(name: "芈月", value: 50.17),DataItem(name: "刘备", value: 52.85),DataItem(name: "娜可露露", value: 48.39),DataItem(name: "橘右京", value: 49.69),DataItem(name: "云樱", value: 49.66),DataItem(name: "镜", value: 47.00),DataItem(name: "司马懿", value: 52.20),DataItem(name: "露娜", value: 49.88),DataItem(name: "猪八戒", value: 48.41),DataItem(name: "阿骨朵", value: 54.28),DataItem(name: "暃", value: 49.67),DataItem(name: "达摩", value: 49.85),DataItem(name: "杨戬", value: 52.44),DataItem(name: "百里玄策", value: 51.75),DataItem(name: "曹操", value: 48.91),DataItem(name: "雅典娜", value: 56.35),DataItem(name: "裴擒虎", value: 47.92),DataItem(name: "云中君", value: 50.68),DataItem(name: "盘古", value: 48.66)]var body: some View {VStack() {Text("2022王者荣耀英雄胜率排行榜").font(.title)HistogramView(title: "打野路英雄胜率(%)", data: chartData)Spacer()}.padding()}
}
  • 对 HistogramView 做出了一些改动,条形图上的值使用叠加视图修改移到了条形图的顶部,这个值是偏移的,因此文本不会离条形图的顶部太近。数据名称的字体大小和字重也可以被设置,像部分英雄名称那样较长的文本,显示出条形图下面的文本将条形图推到了线外。文本视图的宽度被限制在条形图宽度的范围内,而且条形图的标签文本会被截断,条形图的文本视图也被限制在条形宽度的范围内,并且文本可以被隐藏起来:
struct HistogramView: View {var title: Stringvar data: [DataItem]var body: some View {GeometryReader { gr inlet headHeight = gr.size.height * 0.10VStack {HistogramHeaderView(title: title, height: headHeight)HistogramAreaView(data: data).frame(width: CGFloat(data.count) * 70)}}}
}
struct HistogramAreaView: View {var data: [DataItem]var body: some View {GeometryReader { gr inlet fullBarHeight = gr.size.height * 0.90let maxValue = data.map { $0.value }.max()!ZStack {RoundedRectangle(cornerRadius: 5.0).fill(Color(#colorLiteral(red: 0.80, green: 0.90, blue: 0.80, alpha: 1)))VStack {HStack(spacing:0) {ForEach(data) { item inColumnView(name: item.name,value: item.value,maxValue: maxValue,fullBarHeight: Double(fullBarHeight))}}.padding(4)}}}}
}
struct ColumnView: View {var name: Stringvar value: Doublevar maxValue: Doublevar fullBarHeight: Doublevar body: some View {GeometryReader { gr inlet barHeight = (Double(fullBarHeight) / maxValue) * valuelet textWidth = gr.size.width * 0.80VStack {Spacer()RoundedRectangle(cornerRadius: 6.0).fill(Color.red).frame(width: 60, height: CGFloat(barHeight), alignment: .trailing).overlay(Text("\(value, specifier: "%.1f")").font(.footnote).foregroundColor(.white).fontWeight(.regular).frame(width: textWidth).offset(y:8),alignment: .top)Text(name).font(.system(size: 11)).fontWeight(.semibold).lineLimit(5).frame(width: textWidth, alignment: .center)}.padding(.horizontal, 0)}}
}
  • 效果如下:

  • 将视图被嵌入到 ScrollView 中,以便在设备旋转时滚动:
struct ContentView: View {let chartData: [DataItem] = [DataItem(name: "孙悟空", value: 49.40),DataItem(name: "李信", value: 50.68),DataItem(name: "亚瑟", value: 48.41),DataItem(name: "典韦", value: 52.40),DataItem(name: "凯", value: 48.24),DataItem(name: "李元芳", value: 49.53),DataItem(name: "澜", value: 48.76),DataItem(name: "兰陵王", value: 47.08),DataItem(name: "韩信", value: 50.94),DataItem(name: "赵云", value: 50.34),DataItem(name: "程咬金", value: 50.47),DataItem(name: "曜", value: 51.80),DataItem(name: "李白", value: 50.49),DataItem(name: "阿珂", value: 50.77),DataItem(name: "钟无艳", value: 50.68),DataItem(name: "宫本武藏", value: 49.17),DataItem(name: "芈月", value: 50.17),DataItem(name: "刘备", value: 52.85),DataItem(name: "娜可露露", value: 48.39),DataItem(name: "橘右京", value: 49.69),DataItem(name: "云樱", value: 49.66),DataItem(name: "镜", value: 47.00),DataItem(name: "司马懿", value: 52.20),DataItem(name: "露娜", value: 49.88),DataItem(name: "猪八戒", value: 48.41),DataItem(name: "阿骨朵", value: 54.28),DataItem(name: "暃", value: 49.67),DataItem(name: "达摩", value: 49.85),DataItem(name: "杨戬", value: 52.44),DataItem(name: "百里玄策", value: 51.75),DataItem(name: "曹操", value: 48.91),DataItem(name: "雅典娜", value: 56.35),DataItem(name: "裴擒虎", value: 47.92),DataItem(name: "云中君", value: 50.68),DataItem(name: "盘古", value: 48.66)]var body: some View {ScrollView {VStack() {Text("2022王者荣耀英雄胜率排行榜").font(.title)Spacer().frame(height:20)Text("打野路英雄胜率(%)").font(.title3)HistogramView(title: "打野路英雄胜率(%)", data: chartData).frame(width: UIScreen.main.bounds.width - 60, height: 280, alignment: .center)Spacer().frame(height:20)Spacer()}.padding()}}
}
  • 效果如下:

SwiftUI之深入解析如何使用组合矩形GeometryReader创建条形(柱状)图相关推荐

  1. SwiftUI之深入解析高级动画的几何效果GeometryEffect

    一.前言 在我的博客 SwiftUI之深入解析高级动画的路径Paths 中,已经了解了 Animatable 的协议,以及如何使用它来动画路径.接下来,我们将使用相同的协议来动画变换矩阵,使用一个新的 ...

  2. SwiftUI之深入解析如何处理特定的数据和如何在视图中适配数据模型对象

    一.前言 阅读了我的前两篇博客的朋友,应该都熟练掌握了 SwiftUI 如何创建一个任何相关信息的展示视图和各个视图之间的相互组合,以及动态生成一个展示相关信息的可滚动列表,用户可以点击列表项去查看其 ...

  3. SwiftUI之深入解析如何创建列表展示视图和列表如何导航跳转新页面

    一.前言 地标详情页视图已经创建完成,我们需要提供一种方式让用户可以查看完整的地标列表,并且可以查看每一个地标的详情.地标详情页视图的创建,请参考我的博客:SwiftUI之深入解析如何创建和组合视图. ...

  4. R语言层次聚类(hierarchical clustering):使用scale函数进行特征缩放、hclust包层次聚类(创建距离矩阵、聚类、绘制树状图dendrogram,在树状图上绘制红色矩形框)

    R语言层次聚类(hierarchical clustering):使用scale函数进行特征缩放.hclust包层次聚类(创建距离矩阵.聚类.绘制树状图dendrogram,在树状图上绘制红色矩形框) ...

  5. 【Filecoin源码仓库全解析】第二章:如何创建账户钱包并获取FIL Mock代币

    欢迎大家来到第二章,经过 前章<[Filecoin源码仓库全解析]第一章:搭建Filecoin测试节点>的内容阅读后,我们应该已经具备在自己的机器上部署Filecoin测试节点的能力,本章 ...

  6. 【Axure高保真原型】柱状-折线组合图表原型模板

    今天和大家分享柱状-折线组合统计图表的原型模板,该模板用Axure原生元件制作而成,所以样式交互都可以任意修改.该模板用中继器制作,所以使用方便,在中继器表格中填写数据以及坐标最大值,既可以自动生成柱 ...

  7. 20个最佳Flash游戏解析,一步步教你创建Flash游戏

    20个最佳Flash游戏解析,一步步教你创建Flash游戏 http://www.javaeye.com/news/12740-flash Flash算得上是一个家喻户晓的名字,涉及面很广,比如多媒体 ...

  8. python绘制饼状图图例_python matplotlib饼状图参数及用法解析

    这篇文章主要介绍了python matplotlib饼状图参数及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在python的matplo ...

  9. MATLAB | 全网唯一,使用MATLAB绘制矩形树状图

    绘制效果 全网唯一这四个字我都快说腻了,请叫我绘图小天才,又双叒叕写了一个工具函数发到了MATHWORKS,矩形树状图主要用于直观展示各个元素的分类和占比. 编写不易点个赞叭~~ 基本使用 需要准备一 ...

最新文章

  1. eclipse中的git安装与使用
  2. 雷军以前招人标准曝光,写 10 万行代码的直接来 | 极客视频
  3. Git 2.25.0 发布,新特性:部分 clone 与稀疏 checkout
  4. linux下运行gnuplot,Gnuplot Linux版下载
  5. matlab求系统根轨迹代码_根轨迹法、PID参数整定和matlab指令计算
  6. 链表题目---3 合并两个有序单链表 和 分割链表
  7. 基于java百货中心供应链管理系统(含源文件)
  8. codeblock socket 编译错误_在 Go 中使用 Websockets 和 Socket.IO
  9. 985硕士面试20场全被拒,被竞争困住的数据分析人,太难了
  10. 原生js 修改html,原生JS改变HTML内容
  11. Python 信号处理——包络分析
  12. 摄像头视频直播方案比较之方案二:乐橙云
  13. svchost.exe占网速解决方法
  14. 历史论文比赛TCR介绍
  15. 《炬丰科技-半导体工艺》三维硅MEMS结构微加工
  16. frame buffer驱动
  17. 伪造邮件***,看我如何给网易邮箱APP发送垃圾邮件【二】
  18. java获取汉字拼音_Java获取汉字对应的拼音(全拼或首字母)
  19. SpringBoot整合Elasticsearch BBoss
  20. 最长等差数列_最长等差子序列的长度

热门文章

  1. SK海力士将继续投资建设英特尔大连芯片厂
  2. 磷酸铁锂电池回收浸出液除铝
  3. 2020usnews计算机排名布朗,2020usnews布朗大学排名怎么样?
  4. sql数据库连接:用户‘sa’登录失败问题破解(百度加个人总结)
  5. http与https与其他
  6. shineblink 倾倒传感器详解
  7. 网络编程-基于MFC的仿QQ聊天室-2020
  8. [JVM]了断局: 类加载机制
  9. 如何入驻拼多多商城 拼多多入驻形式有那些
  10. SQL server 数据库关系图及数据完整性设计