当前位置: 首页 > 科技观察

如何在SwiftUI中创建条形图

时间:2023-03-15 19:56:47 科技观察

前言条形图将数据类别呈现为矩形条,其宽度和高度与其所代表的值成正比。本文将展示如何创建一个垂直条形图,其中矩形的高度将代表每个类别的值。图表布局入门SwiftUI非常适合探索不同的布局和预览实时视图结果。将部分提取到子视图中很容易,这样每个部分都很小且易于维护。从将包含BarChartView和可能的其他文本或数据的视图开始。此BarChartView包含一个标题和一个图表区域,它们由文本和圆角矩形表示。structChartView1:View{varbody:someView{VStack{Text("示例条形图").font(.title)BarChartView(title:"图表标题").frame(width:300,height:300,alignment:.center)Spacer()}}}structBarChartView:View{vartitle:Stringvarbody:someView{GeometryReader{grinletheadHeight=gr.size.height*0.10VStack{ChartHeaderView(title:title,height:headHeight)ChartAreaView()}}}structChartHeaderView:View{vartitle:Stringvarheight:CGFloatvarbody:someView{Text(title).frame(height:height)}}structChartAreaView:View{varbody:一些视图{ZStack{RoundedRectangle(cornerRadius:5.0).fill(Color(#colorLiteral(red:0.8906477705,green:0.9005050659,blue:0.8208766097,alpha:1)))}}}在图表区添加条形图,定义一些简单的数据类别,比如一周每天的步数,value)。在实际应用中,这里的数据应该是通过ViewModel从模型中获取的。每日步数数据DayStepsMon898Tue670Wed725Thu439Fri1232Sat771Sun365structDataItem:Identifiable{letname:Stringletvalue:Doubleletid=UUID()}structChartView2:View{letchartData:[DataItem]=[DataItem(name:"Mon",value:89,DataItem(名称:“星期二”,值:670),DataItem(名称:“星期三”,值:725),DataItem(名称:“星期四”,值:439),DataItem(名称:“星期五”,值:1232),DataItem(name:"Sat",value:771),DataItem(name:"Sun",value:365)]varbody:someView{VStack{Text("样本条形图").font(.title)BarChartView(title:"Dailystepcount",data:chartData).frame(width:350,height:500,alignment:.center)Spacer()}}}更新BarChartView以便数据可以作为参数传递给ChartAreaViewstructBarChartView:View{vartitle:Stringvardata:[DataItem]varbody:someView{GeometryReader{grinletheadHeight=gr.size.height*0.10VStack{ChartHeaderView(title:title,height:headHeight)ChartAreaView(data:data)}}}}更新后的BarChartView需要一个DataItemGeometryReader的列表用于判断条形图的可用高度。获取数据中的最大值,传递给各个BarView。主图表区域保留其原始的圆角矩形并在水平堆栈中叠加一系列条形图,每个条形图对应一个DataItem。structChartAreaView:View{vardata:[DataItem]varbody:someView{GeometryReader{grinletfullBarHeight=gr.size.height*0.90letmaxValue=data.map{$0.value}.max()!ZStack{RoundedRectangle(cornerRadius:5.0).fill(Color(#colorLiteral(red:0.8906477705,green:0.9005050659,blue:0.8208766097,alpha:1)))VStack{HStack(spacing:0){ForEach(data){iteminBarView(name:item.name,value:item.value,maxValue:maxValue,fullBarHeight:Double(fullBarHeight))}}.padding(4)}}}}}为BarView创建一个新视图,为BarView创建一个新视图每条数据条形图。它需要每个条形的名称和值以及最大和可用的条形高度。每个条形图都表示为一个圆角矩形,条形图高度设置为相对于最大条形图高度。条形的颜色设置为纯蓝色。structBarView:View{varname:Stringvarvalue:DoublevarmaxValue:DoublevarfullBarHeight:Doublevarbody:someView{letbarHeight=(Double(fullBarHeight)/maxValue)*valueVStack{Spacer()ZStack{VStack{Spacer()RoundedRectangle(cornerRadius:5.0).fill(Color.blue).frame(height:CGFloat(barHeight),alignment:.trailing)}VStack{Spacer()Text("\(value,specifier:"%.0F")").font(.footnote).foregroundColor(.white).fontWeight(.bold)}}Text(name)}.padding(.horizo??ntal,4)}}使用示例数据时屏幕旋转条形图看起来不错。图表适合它所在的容器视图。相同的图表可以放在没有其他视图的任何新视图上,并且当设备旋转时,图标将填充空间并调整大小。structChartView3:View{varbody:someView{VStack(){BarChartView(title:"每日步数",data:chartData)Spacer()}.padding()}}手机显示的图表真实数据条rotatesGraph使用真实世界的数据制作条形图。联合国儿童基金会数据集中五岁以下儿童死亡率最高的十个国家。五岁以下儿童死亡率:指每1,000名活产婴儿在出生和五岁之间死亡的概率2019年ISO代码国名2019NGANigeria117.2SOMSomalia116.9TCDChad113.7CAFCentralAfricanRepublic110.0SLESierraLeone109.2GINGuinea98的特定国家/地区五岁以下儿童死亡率估计值。8SSSDSouthSudan96.2MLIMali94.0BENBenin90.2BFABurkinaFaso87.5LSOLesotho86.4可以看出使用多个数据名称的示例数据中的国名比星期几要长很多。数据使用国家名称绘制在条形图中。structChartView4:View{letchartData:[DataItem]=[DataItem(name:"Nigeria",value:117.2),DataItem(name:"Somalia",value:116.9),DataItem(name:"Chad",值:113.7),DataItem(名称:"中非共和国",值:110.0),DataItem(名称:"塞拉利昂",值:109.2),DataItem(名称:"几内亚",值:98.8),DataItem(名称:"南苏丹",价值:96.2),DataItem(名称:"马里",价值:94.0),DataItem(名称:"贝宁",价值:90.2),DataItem(名称:"布基纳法索",价值:87.5)]varbody:someView{VStack(){BarChartView(title:"2019年五岁以下儿童死亡率",data:chartData).frame(width:350,height:500,alignment:.center)Text("五岁以下儿童死亡率:")Text("是从出生到5岁之间死亡的概率,以每1,000名活产婴儿表示。")Spacer()}.padding()}}此处对BarView进行了一些更改,使用覆盖视图修改将栏上的值移动到栏的顶部。这个值是偏移的,所以文本不会离栏的顶部太近。还可以设置数据名称的字体大小和粗细。较长的文本(如国家/地区名称)表明条形下方的文本将条形推出了该行。textview的宽度限制为bar的宽度,bar的标签文本被截断,bar的textview也限制为bar的宽度,可以隐藏文字。structBarView:View{varname:Stringvarvalue:DoublevarmaxValue:DoublevarfullBarHeight:Doublevarbody:someView{GeometryReader{grinletbarHeight=(Double(fullBarHeight)/maxValue)*valuelettextWidth=gr.size.width*0.80VStack{Spacer()RoundedRectangle(cornerRadius:5.0).fill(Color.blue).frame(height:CGFloat(barHeight),alignment:.trailing).overlay(Text("\(value,specifier:"%.0F")").font(.footnote).foregroundColor(.white).fontWeight(.bold).frame(width:textWidth).offset(y:10),对齐方式:.top)Text(name)。字体(.system(size:11)).fontWeight(.semibold).lineLimit(1).frame(width:textWidth)}.padding(.horizo??ntal,4)}}}所有国家名称都被截断了,因此将数据改为Insteadof使用国家代码而不是国家名称将图标设置为固定大小,并将视图嵌入到ScrollView中,以便在设备旋转时滚动。structChartView5:View{letchartData:[DataItem]=[DataItem(名称:"NGA",值:117.2),DataItem(名称:"SOM",值:116.9),DataItem(名称:"TCD",值:113.7),DataItem(名称:"CAF",值:110.0),DataItem(名称:"SLE",值:109.2),DataItem(名称:"GIN",值:98.8),DataItem(名称:"SSD",值::96.2),DataItem(名称:“MLI”,值:94.0),DataItem(名称:“BEN”,值:90.2),DataItem(名称:“BFA”,值:87.5)]varbody:一些视图{ScrollView{VStack(){BarChartView(title:"2019年五岁以下儿童死亡率最高的国家",data:chartData).frame(width:350,height:500,alignment:.center)Spacer().frame(height:20)VStack(){Text("五岁以下儿童死亡率:").font(.system(.title2,design:.rounded)).fontWeight(.bold)Text("是从出生到5岁之间死亡的概率,以每1,000名活产婴儿表示。").font(.body)}.frame(width:300,height:130).background(Color(#colorLiteral(red:0.8906477705,green:0.9005050659,blue:0.8208766097,alpha:1))).cornerRadius(10)Spacer()}.padding()}}}创建条形图相对简单SwiftUI是创建视图和快速重构单个子视图的绝佳平台。在SwiftUI中构建条形图需要一些工作,当您使用数据对条形图进行试验时,可以确定更多的自定义设置。使用GeometryReader创建适应更多可用环境的条形图。在本文中,我们创建了一个简单的条形图,其中包含值、下方标签和图表标题。下一步是分离x轴和y轴。