Olaf⛄️ 2022-8-12终稿

前言

作为一个iOS开发者,咱们在日常开发中,多多少少会遇到图标展现类的需求,信任我们解决图标需求时,都会直接运用或许参阅github开源的图表制作结构:Charts,这个根据CoreGraphics制作图表的结构,支撑了相当一部分的图表开发需求。

2022,Apple自己的图表结构来了!

全新的 Swift Charts 结构在WWDC22中跟开发者碰头了。这是一个强壮而简练的SwiftUI结构,能将数据转换为信息丰富的可自定义可视化图表。下面是相关的4个Session:

强力主张观看Session!!!

结构特性

WWDC22- Swift Charts初探

上图是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吧

WWDC22- Swift Charts初探

结构实践

完成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()
    }
}

咱们看出现作用:

WWDC22- Swift Charts初探

假如这项开支还需求跟另一项开支进行比照出现,这该怎么完成呢?咱们只需求将上面的代码略微改动,即可完成,一下只张贴新增部分的代码:

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)
  }
}

咱们再来看看出现作用:

WWDC22- Swift Charts初探

现在现已完成了几个国家两个费用支出的比照图。比照上面,在代码上除了新增数据源,在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()
    }
}

咱们来看作用:

WWDC22- Swift Charts初探

假如想给折线图添加一个数据点的符号符号,一起让折线变的圆润,那咱们就需求完成以下两个特点

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)
    }
}

再看下作用:

WWDC22- Swift Charts初探

此刻咱们能够看到数据节点都用原点符号出来,并且折线也变成了愈加柔和的曲线,这便是 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)
    }
}

相同咱们先来看看作用:

WWDC22- Swift Charts初探

相同,AreaMark也运用了interpolationMethod来添加了边际的曲线,一起还运用foregroundStyle来设置区域的色彩。

更多支撑

Swift Charts能够三种数据类型作为他的数据值

WWDC22- Swift Charts初探

  • Quantitative(数据型,假如Int、Double等)

  • Nominal(名义型,如各类称号标签)

  • Temporal(时刻型,如年月周日时分等)

所以,6种Mark实践只要三种数据类别,每种Mark一般运用的特点通产个包括以下这些,这些特点,咱们再上面的实践Demo中也都有运用到:

WWDC22- Swift Charts初探

那么这些特点是不是足够了呢?

当然,是不行的。咱们在实践开发中出现的UI需求往往是定制化元素比较多的,现在咱们来看看Swift Charts 结构都能够支撑哪些内容的自定义,Seesion中给咱们罗列了Chart的自定义内容维度:

WWDC22- Swift Charts初探

接下来,我从途中所列的自定义特点入手,结合上面的的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)
            // 此刻的作用,下图二

WWDC22- Swift Charts初探
WWDC22- Swift Charts初探

当然,关于这三个特点的应用,不止于此。它们都有很强壮的自定义支撑才能来应对图标的展现需求,再结合Descriptions、Interaction、Color来完成愈加酷炫的图表出现。

关于运用

Charts的图表出现才能尽管强壮,可是咱们都知道图表有它特别的出现场景,那么何时应该较交互出现为图表,苹果的Session中现已给咱们进行的设计指引。

当咱们需求将数据进行改变、比照、进展(比例)出现时,咱们就能够运用Chart来帮咱们进行可视化的完成 了。

WWDC22- Swift Charts初探
WWDC22- Swift Charts初探
WWDC22- Swift Charts初探

如上三张图所示:

  • 当咱们需求可视化某项继续性数据改变趋势时,咱们就能够运用Change部分的可视化方法来出现。例如:用户单日步数、用户消费、阅读时长等数据改变趋势。

  • 当咱们需求可视化某项任务的进展,完成度、参与度、占比等等数据时,咱们就能够运用Proportion部分的可视化方式来出现。例如:用户年度App各类事务消费占比。

  • 当咱们需求可视化更全面数据的比照及跟维度的数据时,咱们能够运用Comparison部分的可视化方式来出现。如各公司的数据渠道等体系的数据。

综上,Charts的运用场景,可能依然是很多App中的小部分,可是在特定行业App的事务中则是中心才能的展现,如你需求做一个股票或许财经类的App,又或许关于健康数据的App。Apple Watch的应用中则对Swift Charts有更多的需求。下面咱们能够看看Session中的一些案例。

WWDC22- Swift Charts初探

写在最终

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)