Olaf⛄️ 2022-8-12终稿
前言
作为一个iOS开发者,咱们在日常开发中,多多少少会遇到图标展现类的需求,信任我们解决图标需求时,都会直接运用或许参阅github开源的图表制作结构:Charts,这个根据CoreGraphics制作图表的结构,支撑了相当一部分的图表开发需求。
2022,Apple自己的图表结构来了!
全新的 Swift Charts 结构在WWDC22中跟开发者碰头了。这是一个强壮而简练的SwiftUI结构,能将数据转换为信息丰富的可自定义可视化图表。下面是相关的4个Session:
强力主张观看Session!!!
结构特性
上图是Seesion中的作用出现、展现了Swift Charts强壮的制作才能,从简略的柱状图到复杂的向量图,热力求,Swift Charts都能够用简练的代码完成。Swift Charts 支撑 localization 本地化 和 accessibility 辅助功用。还能够运用图表修饰符掩盖默许行为以自定义图表。 例如,能够经过向图表添加动画来创立动态体验。
兼容性
iOS 16+、iPadOS 16.0+、macOS 13.0+、watchOS 9.0+
Marks
-
BarMark
能够运用BarMark创立不同类型的条形图,如柱状图,进展条图等。
-
LineMark
能够经过制作类别或日期特点(一般运用 x 位置)和制作数字类别(一般运用 y 位置)来创立折线图。
-
PointMark
能够运用 PointMark 图表内容创立不同类型的点图表。能够运用点符号构建的一个常见图表是散点图,它显示两个数值数据特点之间的联系。
-
AreaMark
能够运用 AreaMark 将数据可视化为单个区域形状。 能够运用 AreaMark 图表内容创立不同类型的面积图。 要创立简略的区域符号图表,咱们一般会将日期或有序字符串特点制作到 x 位置,将数字制作到 y 位置。
-
RuleMark
能够运用 RuleMark 在图表中制作水平或笔直规矩,如平均线,阈值线等。
-
RectangleMark
能够运用RectangleMark将数据字段映射成矩形图。 能够运用RectangleMark创立热图图表或注释图表中的矩形区域。
以上便是Swift Charts一切的Mark,它们能够独自运用,也能够组合运用,从而支撑开发者按需求开发出所需求的图表。用Session中的图来总结这些Mark吧
结构实践
完成Swift Charts结构,首要需求对SwiftUI的语法有必定的了解,下面将挑选典型图表进行coding实践。
BarkMark
假如咱们需求用一张图表来直观的出现多个国家的某一项开支费用,那咱们就能够直接用BarMark来构建一个简略的柱状图来完成。
struct BarMarkData: Identifiable {
let name: String
let count: Double
var id: String{name}
}
let defData: [BarMarkData] = [
BarMarkData(name: "China", count: 15000),
BarMarkData(name: "US", count: 30000),
BarMarkData(name: "UK", count: 2000),
BarMarkData(name: "Japan", count: 800),
BarMarkData(name: "France", count: 3000)
]
struct BarMarkChartView: View {
var body: some View {
Chart(data) {
BarMark(
x: .value("name", $0.name),
y: .value("count", $0.count)
)
}.frame(width: 360, height: 300)
}
}
struct BarMarkChartView_Previews: PreviewProvider {
static var previews: some View {
AreaMarkChartView()
}
}
咱们看出现作用:
假如这项开支还需求跟另一项开支进行比照出现,这该怎么完成呢?咱们只需求将上面的代码略微改动,即可完成,一下只张贴新增部分的代码:
let eduData: [BarMarkData] = [
BarMarkData(name: "China", count: 28000),
BarMarkData(name: "US", count: 35000),
BarMarkData(name: "UK", count: 6000),
BarMarkData(name: "Japan", count: 2000),
BarMarkData(name: "France", count: 5000)
]
let mergeData = [
(outlay: "def", data: defData),
(outlay: "edu", data: eduData)
]
struct AreaMarkChartView: View {
var body: some View {
Chart(mergeData, id: .outlay) { mergeData in
ForEach(defData) { datum in
ForEach(mergeData.data, id: .id) { element in
BarMark(
x: .value("name", element.name),
y: .value("count", element.count)
).position(by: .value("outlay", mergeData.outlay))
.foregroundStyle(by: .value("outlay", mergeData.outlay))
}
}
}.frame(width: 360, height: 300)
}
}
咱们再来看看出现作用:
现在现已完成了几个国家两个费用支出的比照图。比照上面,在代码上除了新增数据源,在Charts完成环节,也新增了position和foregroundStyle两个扩展办法
-
.position
position能够创立分组,让图表沿水平轴按其“类型”符号具有相同“产品”的mark。
-
.foregroundStyle
foregroundStyle依照传参不同,可进行不同类型的展现设置,如下:
extension ChartContent {
/// Sets the foreground style for marks in this chart content.
///
/// - Parameter color: The color.
public func foregroundStyle<S>( _ style: S) -> some ChartContent where S : ShapeStyle
/// Encodes data as the foreground style for marks in this chart content.
///
/// - Parameter data: The data property or value.
public func foregroundStyle<D>(by value: PlottableValue<D>) -> some ChartContent where D : Plottable
}
LineMark
假如咱们需求展现公司计算的一年内营收数据的改变,并且比照从前的数据,那此刻咱们能够用到的最简略的图便是线性图了,当然咱们也能够运用其他的类型的图表来表示。下面咱们先用LineMark来进行实践
struct SalesSummary: Identifiable {
let month: String
let total: Int
var id: String {month}
}
let pastData: [SalesSummary] = [
.init(month: "Jan", total: 3388),
.init(month: "Feb", total: 4420),
.init(month: "Mar", total: 6120),
...
.init(month: "Dec", total: 11076)
]
let lineData: [SalesSummary] = [
.init(month: "Jan", total: 5566),
.init(month: "Feb", total: 4610),
.init(month: "Mar", total: 5533),
...
.init(month: "Dec", total: 12998)
]
let salesData = [
(quarter: "2022", data: currentData),
(quarter: "2021", data: pastData)
]
struct LineMarkChartView: View {
var body: some View {
Chart{
ForEach(salesData, id: .years) { salesData in
ForEach(salesData.data, id: .id) { element in
LineMark(x: .value("month", element.month),
y: .value("total", element.total))
}.foregroundStyle(by: .value("sales", salesData.years))
}
}.frame(width: 360, height: 300)
}
}
struct LineMarkChartView_Previews: PreviewProvider {
static var previews: some View {
LineMarkChartView()
}
}
咱们来看作用:
假如想给折线图添加一个数据点的符号符号,一起让折线变的圆润,那咱们就需求完成以下两个特点
struct LineMarkChartView: View {
var body: some View {
Chart{
ForEach(salesData, id: .years) { salesData in
ForEach(salesData.data, id: .id) { element in
LineMark(x: .value("month", element.month),
y: .value("total", element.total))
.interpolationMethod(.catmullRom)
.symbol(by: .value("sales", salesData.years))
}.foregroundStyle(by: .value("sales", salesData.years))
}
}.frame(width: 360, height: 300)
}
}
再看下作用:
此刻咱们能够看到数据节点都用原点符号出来,并且折线也变成了愈加柔和的曲线,这便是 interpolationMethod 和 symbol 这两个特点发挥的作用。
-
interpolationMethod
回来运用给定插值制作数据的图表内容,包含多个,这儿纷歧一列举了,能够检查api,这个办法仅提供给Line 和 Area 两种Mark
-
symbol
symbol根据传参不同有三个不同的办法完成,来支撑不同的特性功用
extension ChartContent {
/// 设置此图表内容中符号的绘图符号类型
/// - Parameter symbol: The symbol.
public func symbol<S>( _ symbol: S) -> some ChartContent where S : ChartSymbolShape
/// 将数据编码为此图表内容中符号的符号。如上面的比如
/// - Parameter data: The data property or value.
public func symbol<D>(by value: PlottableValue<D>) -> some ChartContent where D : Plottable
/// 回来以给定视图作为绘图符号的图表内容。
/// - Parameter symbol: The view to use as the plotting symbol.
public func symbol<V>(@ViewBuilder symbol: () -> V) -> some ChartContent where V : View
}
AreaMark
上面的公司年度营收的折线图数据相同也能够用来实践AreaMark区域图,咱们来看看详细的代码完成,会不会更复杂呢,仍是相同简略
let areaData: [BarMarkData] = [
.init(month: "Jan", total: 5566),
.init(month: "Feb", total: 4610),
.init(month: "Mar", total: 5533),
...
.init(month: "Dec", total: 12998)
]
struct AreaMarkChartView: View {
var body: some View {
Chart(areaData) { element in
AreaMark(
x: .value("month", element.month),
y: .value("total", element.total)
).interpolationMethod(.catmullRom)
.foregroundStyle(.pink)
}.frame(width: 360, height: 300)
}
}
相同咱们先来看看作用:
相同,AreaMark也运用了interpolationMethod来添加了边际的曲线,一起还运用foregroundStyle来设置区域的色彩。
更多支撑
Swift Charts能够三种数据类型作为他的数据值
-
Quantitative(数据型,假如Int、Double等)
-
Nominal(名义型,如各类称号标签)
-
Temporal(时刻型,如年月周日时分等)
所以,6种Mark实践只要三种数据类别,每种Mark一般运用的特点通产个包括以下这些,这些特点,咱们再上面的实践Demo中也都有运用到:
那么这些特点是不是足够了呢?
当然,是不行的。咱们在实践开发中出现的UI需求往往是定制化元素比较多的,现在咱们来看看Swift Charts 结构都能够支撑哪些内容的自定义,Seesion中给咱们罗列了Chart的自定义内容维度:
接下来,我从途中所列的自定义特点入手,结合上面的的Demo比如,进一步实践Swift Charts的自定义才能。
添加Plot特点后,咱们看看实践的作用
.chartPlotStyle { plot in
plot.background(.purple.opacity(0.8))
.border(.purple, width: 2)
.frame(width: 150, height: 100)
}
// 此刻的作用,下图一。
// 假如将这个图标展现在Apple Watch,或许Widget上,
// 坐标线的作用此刻会成为一种干扰,当然咱们能够躲藏坐标线
.chartXAxis(.hidden)
.chartYAxis(.hidden)
// 此刻的作用,下图二
当然,关于这三个特点的应用,不止于此。它们都有很强壮的自定义支撑才能来应对图标的展现需求,再结合Descriptions、Interaction、Color来完成愈加酷炫的图表出现。
关于运用
Charts的图表出现才能尽管强壮,可是咱们都知道图表有它特别的出现场景,那么何时应该较交互出现为图表,苹果的Session中现已给咱们进行的设计指引。
当咱们需求将数据进行改变、比照、进展(比例)出现时,咱们就能够运用Chart来帮咱们进行可视化的完成 了。
如上三张图所示:
-
当咱们需求可视化某项继续性数据改变趋势时,咱们就能够运用Change部分的可视化方法来出现。例如:用户单日步数、用户消费、阅读时长等数据改变趋势。
-
当咱们需求可视化某项任务的进展,完成度、参与度、占比等等数据时,咱们就能够运用Proportion部分的可视化方式来出现。例如:用户年度App各类事务消费占比。
-
当咱们需求可视化更全面数据的比照及跟维度的数据时,咱们能够运用Comparison部分的可视化方式来出现。如各公司的数据渠道等体系的数据。
综上,Charts的运用场景,可能依然是很多App中的小部分,可是在特定行业App的事务中则是中心才能的展现,如你需求做一个股票或许财经类的App,又或许关于健康数据的App。Apple Watch的应用中则对Swift Charts有更多的需求。下面咱们能够看看Session中的一些案例。
写在最终
Swift Charts是在WWDC22上和我们碰头的,其强壮的图表出现才能,随着你对结构的发掘和了解,会逐步感知到。那么当你看了这篇文章后,你对Swift Charts有什么主意?
-
好家伙,兼容性最低iOS16,哪年那月才能用上…
-
根据SwiftUI,我还不如用danielgindi/Charts,毕竟SwiftUI也得最低iOS13的支撑,等到那时候再看SwiftUI吧…
这些问题确确实实存在,并且当你了解Swift Charts后,也必定会发现有它所不能支撑的需求场景。Swift Charts在WWDC22和我们碰头,我信任在WWDC23/24或许更远的将来,Swift Charts结构也会继续的更新和改进,有Widget Kit开发需求,或许Apple Watch开发需求的小伙伴,主张继续坚持关注。
参阅文献
- Session 10136 – Hello Swift Charts
- Session 10137 – Swift Charts: Raise the bar
- Session 110340 – Design an effective chart
- Session 110342 – Design app experiences with charts
- Apple Developer(Charts)