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

在Swift图表中使用Foudation库中的测量类型

时间:2023-03-17 23:22:21 科技观察

前言在这篇文章中,我们将构建一个条形图来比较基督城地区自然漫步的持续时间。我们将使用今年推出的新SwiftCharts框架,看看如何绘制默认情况下不符合Plottable协议的类型的数据,例如Measurement。为图表定义数据让我们首先定义要在图表中显示的数据。我们声明一个Walk结构,其中包含标题和以小时为单位的步行时间。我们使用Foundation框架中的度量类型Measurement[1]和单位类型UnitDuration[2]来表示每次行走的时间。structWalk{lettitle:Stringletduration:Measurement}我们将要在图表中显示的数据存储在数组works中。letwalks=[Walk(title:"TaylorsMistaketoSumnerBeachCoastalWalk",duration:Measurement(value:3.1,unit:.hours)),Walk(title:"瓶湖森林",duration:Measurement(value:2),unit:.hours)),Walk(title:"OldHalswellQuarryLoop",duration:Measurement(value:0.5,unit:.hours)),...]在图表中使用测量值尝试直接在图表中使用测量值.让我们定义一个Chart并将walks数组作为数据参数传递给它。因为我们知道我们的步行标题是独一无二的,所以我们可以直接将它们用作ID,但您也可以将数据模型更改为可识别。Chart(walks,id:\.title){walkinBarMark(x:.value("Duration",walk.duration),y:.value("Walk",walk.title))}请注意,因为Measurement不遵循Plottable协议,我们得到一个错误:“Initializer'init(x:y:width:height:stacking:)'requiresthat'Measurement'conformto'Plottable'”BarkMark的初始化程序期望收到一个x和y的PlottableValue参数。并且PlottableValue的值类型必须符合Plottable协议。我们有几个选项可以解决此错误。我们可以提取测量的值,它是默认符合Plottable的Double类型,我们可以扩展符合Plottable的Measurement,或者我们可以定义一个包装测量的类型并使其符合Plottable协议.如果我们简单地从测量中提取,我们就失去了使用什么单位来创建测量的上下文。这意味着我们将无法正确设置图表标签的格式来向用户表示单位。虽然我们记得我们在创建测量时使用了几个小时,但这并不理想。例如,我们可能决定稍后更改数据模型以以分钟为单位存储持续时间,或者数据可能来自其他地方,因此手动重构单位并不是一个完美的解决方案。可以使用PlottableConformances扩展Measurement,但是根据WarningforRetroactiveConformancesofExternalTypesinSwift(WarningforRetroactiveConformancesofExternalTypes[3]),如果SwiftCharts在未来的一致性中添加这个,它可能坏了。我们将看看如何定义我们自己的类型来包装测量并将Plottable一致性添加到我们的自定义类型。设计包装类型设计符合Plottable标准的包装类型。我们将定义一个自定义PlottableMeasurement类型并使其通用,以便它可以容纳任何类型的测量类型单位。structPlottableMeasurement{varmeasurement:Measurement}然后,我们将Plottable的一致性添加到单位类型为UnitDuration的PlottableMeasurement。我们将来可能会增加对其他单位的支持。扩展PlottableMeasurement:Plottable其中UnitType==UnitDuration{varprimitivePlottable:Double{self.measurement.converted(to:.minutes).value}init?(primitivePlottable:Double){self.init(measurement:Measurement(value:primitivePlottable,unit:.minutes))}}Plottable协议有两个要求:primitivePlottable属性必须返回一种原始类型,例如Double、String或Date,以及一个从原始可绘制类型创建值的可失败初始化程序。我决定将测量值转换为分钟,但您可以选择适合您需要的任何其他单位。从原始值转换时使用相同的单位很重要。我们现在可以更新我们的图表以使用我们的自定义Plottable类型。Chart(walks,id:\.title){walkinBarMark(x:.value("Duration",PlottableMeasurement(measurement:walk.duration)),y:.value("Walk",walk.title))}它有效,但x轴上的标签未格式化,并且未向用户显示测量单位。我们接下来会解决这个问题。显示格式标签显示带有度量单位的格式标签。要自定义x轴上的标签,我们将使用chartXAxis(content:)修饰符并使用传递给我们的值重构x轴标签。Chart(walks,id:\.title){...}.chartXAxis{AxisMarks{AxisGridLine()中的值AxisValueLabel("""\(value.as(PlottableMeasurement.self)!.measurement.converted(to:.hours),format:.measurement(width:.narrow,numberFormatStyle:.number.precision(.fractionLength(0))))""")}}我们首先添加网格线,然后重建给定值的标签。AxisValueLabel在初始化器中接受LocalizedStringKey,它可以通过插值测量并指定其格式样式来构造。我们收到的值是使用我们在Plottable一致性中定义的初始化器创建的,因此在我们的例子中,测量值以分钟为单位提供。但我相信对于这个特定的图表,使用小时会更好。我们可以轻松地将测量值转换为插值所需的单位。在这里,我们确保该值是PlottableMeasurement类型,因此我们可以强制进行解包类型转换。我选择缩小格式和小数位数作为数字样式,但您可以针对您的特定图表调整这些设置。最终结果是在x轴上显示以小时为单位的格式化持续时间。您可以从我们的GitHub存储库[4]中获取本文中使用的项目的完整示例代码。参考文献[1]测量:https://developer.apple.com/documentation/foundation/measurement。[2]UnitDuration:https://developer.apple.com/documentation/foundation/unitduration。[3]外部类型的追溯一致性警告:https://github.com/apple/swift-evolution/blob/main/proposals/0364-retroactive-conformance-warning.md。[4]示例代码:https://github.com/SwiftCommunityRes/SwiftUI-Code-Examples/blob/main/Using-Measurements-from-Foundation-as-values-in-Swift-Charts/Using-Measurements-from-Foundation-as-values-in-Swift-Charts.swift。