WWDC Quick Look 💓 By SwiftGGTeam
Hello Swift Charts

Hello Swift Charts

观看原视频

Highlight

Swift Charts 是 Apple 在 WWDC 2022 发布的声明式图表框架,完全基于 SwiftUI 语法。它用 Mark(标记)的概念统一了所有图表类型——BarMark、LineMark、PointMark 等——你通过组合这些 Mark 来构建图表,就像在 SwiftUI 中组合 View 一样。Session 用一个煎饼销量追踪 App,从零展示了柱状图、多系列对比图和组合图表的构建过程。


核心内容

Swift Charts 解决了一个长期存在的问题:在 Apple 平台上做数据可视化,要么用第三方库,要么自己画 Core Graphics。这两个选项都很重。

新的 Swift Charts 框架带来了声明式图表语法。你只需要描述数据映射关系——“x 轴是日期,y 轴是销量”——框架自动处理坐标轴、刻度、图例和交互。

Session 中用一个 Pancake Food Truck 应用演示了三种典型场景。这个 App 记录 Cupertino 和 San Francisco 两个城市不同煎饼品种的销量数据。

第一个场景是柱状图,展示各品种总销量排名。代码很简单:

Chart(panSales) {
    BarMark(
        x: .value("Pancake", $0.type),
        y: .value("Sales", $0.sales)
    )
}

这里的 .value() 方法很关键——第一个参数是标签描述,第二个参数是实际值。框架用这个描述来生成轴标签和无障碍 VoiceOver 描述,而不只是显示原始数值。

第二个场景是多系列对比。应用中加入了城市选择器,用 SwiftUI Picker 切换 Cupertino 和 San Francisco 的数据。加一行 .foregroundStyle(by: .value("City", $0.city)) 就能按城市着色区分。

第三个场景是组合图表,把两个城市的数据叠在同一张图里。LineMark 画折线,PointMark 标注数据点,.foregroundStyle(by:) 自动分配颜色和生成图例。


详细内容

BarMark:柱状图的基础

Swift Charts 的核心理念是 Mark。每种图表类型对应一种 Mark,就像 SwiftUI 中每种 UI 元素对应一种 View。

BarMark 是最基础的 Mark,用来创建柱状图。初始化需要 x 和 y 两个维度:

Chart(salesData) { sale in
    BarMark(
        x: .value("品种", sale.pancakeType),
        y: .value("销量", sale.count)
    )
}

Chart 构造器接受一个 RandomAccessCollection,数组中的每个元素对应图表上的一个数据点。如果你的数据遵循 Identifiable,可以直接传入集合。

想让柱状图变成横向?交换 x 和 y 的值即可:

BarMark(
    x: .value("销量", sale.count),
    y: .value("品种", sale.pancakeType)
)

框架自动调整轴标签方向和布局,不需要手动计算 frame 或旋转视图。

多系列与动态数据

当图表包含多个数据系列时,.foregroundStyle(by:) 是关键 modifier:

Chart(salesByCity) { sale in
    BarMark(
        x: .value("日期", sale.date, unit: .day),
        y: .value("销量", sale.count)
    )
    .foregroundStyle(by: .value("城市", sale.city))
}

框架自动为每个城市分配颜色、生成图例。配合 SwiftUI 的 .animation() 可以让数据切换时图表平滑过渡:

Chart(filteredSales) { ... }
    .animation(.easeInOut, value: selectedCity)

这段代码的意思是:当 selectedCity 变化导致数据过滤结果改变时,图表以 easeInOut 曲线动画过渡到新状态。

LineMark 和 PointMark 的组合

折线图使用 LineMark,和 BarMark 语法几乎一致:

Chart(salesByDate) { sale in
    LineMark(
        x: .value("日期", sale.date),
        y: .value("销量", sale.count)
    )
    .foregroundStyle(by: .value("城市", sale.city))
}

加上 PointMark 可以在折线的每个数据点上显示标记:

Chart(salesByDate) { sale in
    LineMark(
        x: .value("日期", sale.date),
        y: .value("销量", sale.count)
    )
    .foregroundStyle(by: .value("城市", sale.city))

    PointMark(
        x: .value("日期", sale.date),
        y: .value("销量", sale.count)
    )
    .foregroundStyle(by: .value("城市", sale.city))
}

这种组合模式是 Swift Charts 设计的关键——不同 Mark 可以自由叠加,框架统一处理坐标映射。

其他图表类型

Session 最后快速展示了 Swift Charts 支持的其他 Mark 类型:

// 面积图
AreaMark(
    x: .value("日期", data.date),
    y: .value("值", data.value)
)

// 规则线(阈值线)
RuleMark(
    y: .value("目标", targetValue)
)

// 矩形(热力图)
RectangleMark(
    x: .value("列", data.col),
    y: .value("行", data.row)
)

每种 Mark 的 API 都遵循相同的模式:x 和 y 维度用 .value() 描述映射关系,数据通过 Chart 初始化器传入。


核心启发

  • Mark 组合模式是框架的灵魂:不把图表看作固定模板(柱状图/折线图/饼图),而是看作 Mark 的组合。LineMark + PointMark 是常见搭配,AreaMark + LineMark 也可以叠加。这种设计让自定义图表变得自然,不用学另一套 DSL。
  • .value() 不只是设值,是为无障碍和轴标签提供语义:第一个参数会被 VoiceOver 朗读、被轴标签引用。写 .value("销量", count) 而不仅仅是传 count,这个习惯值得从一开始就养成。
  • 数据驱动动画几乎零成本:用 .animation(.easeInOut, value: selectedCity) 一行代码就能让图表数据切换时平滑过渡。这是 SwiftUI 声明式范式在图表领域的自然延伸——你声明数据变化,框架负责动画。
  • 转置图表不需要改数据,交换 x/y 就行:横向柱状图、纵向柱状图的切换只是 BarMark(x:y:) 两个参数的顺序问题。框架自动处理坐标轴方向、标签位置和布局。
  • Identifiable 数据模型让代码更简洁:让数据 struct 遵循 IdentifiableChart 可以直接用数组初始化,ForEach 也不需要指定 id。这是 SwiftUI 数据流的最佳实践在 Charts 中的延续。

关联 Session

评论

GitHub Issues · utterances