前言

苹果在 WWDC 2022 上推出了 SwiftUI 图表,这使得在 SwiftUI 视图中创立图表变得反常简略。图表是以丰富的格式呈现可视化数据的一种很好的方式,并且易于了解。本文展现了如何用比曾经从头开端创立相同的折线图少得多的代码轻松创立折线图。此外,自界说图表的外观和感觉以及使图表中的信息易于拜访也是非常简单的。

如曾经的文章所示,不运用 SwiftUI Charts 也能够创立一个折线图。然而,运用 Charts 结构能够提供大量的图表来探究对应用程序中的数据最有用的办法,从而使它变得更加简单。

系列文章

  1. 如安在 SwiftUI 中创立条形图
  2. SwiftUI 中的水平条形图
  3. iOS 16 顶用 SwiftUI Charts 创立一个折线图
  4. 在 iOS16 顶用 SwiftUI 图表定制一个线图
  5. 在 Swift 图表中运用 Foudation 库中的丈量类型

简略折线图

从包括一周的步数的数据开端,类似于 在SwiftUI中创立折线图 中运用的数据。界说一个结构来保存日期和该日的步数,并为当时周创立一个数组。

struct StepCount: Identifiable {
    let id = UUID()
    let weekday: Date
    let steps: Int
    init(day: String, steps: Int) {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        self.weekday = formatter.date(from: day) ?? Date.distantPast
        self.steps = steps
    }
}
let currentWeek: [StepCount] = [
    StepCount(day: "20220717", steps: 4200),
    StepCount(day: "20220718", steps: 15000),
    StepCount(day: "20220719", steps: 2800),
    StepCount(day: "20220720", steps: 10800),
    StepCount(day: "20220721", steps: 5300),
    StepCount(day: "20220722", steps: 10400),
    StepCount(day: "20220723", steps: 4000)
]

要创立一个折线图,为步数数据中的每个元素创立一个带有LineMark的图表。在LineMark的 X 值中指定工作日,在 Y 值中指定步数。注意,还需要导入Charts结构。

这就为步数数据创立了一个线形图。因为只有一个系列的数据,ForEach 能够省略,数据能够直接传递给 Chart 初始化器。两个部分都发生相同的折线图。

import SwiftUI
import Charts
struct LineChart1: View {
    var body: some View {
        VStack {
            GroupBox ( "Line Chart - Step Count") {
                Chart {
                    ForEach(currentWeek) {
                        LineMark(
                            x: .value("Week Day", $0.weekday, unit: .day),
                            y: .value("Step Count", $0.steps)
                        )
                    }
                }
            }
            GroupBox ( "Line Chart - Step Count") {
                Chart(currentWeek) {
                    LineMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
        }
    }
}

在 iOS 16 中用 SwiftUI Charts 创建一个折线图

运用 SwiftUI Charts 创立的折线图显现每日步数

其他图表

SwiftUI Charts 有许多可用的图表选项。这些能够经过将图表标记从LineMark改为其他类型的标记(如BarMark)来生成条形图。

struct OtherCharts: View {
    var body: some View {
        VStack {
            GroupBox ( "Line Chart - Step count") {
                Chart(currentWeek) {
                    LineMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            GroupBox ( "Bar Chart - Step count") {
                Chart(currentWeek) {
                    BarMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            GroupBox ( "Point Chart - Step count") {
                Chart(currentWeek) {
                    PointMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            GroupBox ( "Rectangle Chart - Step count") {
                Chart(currentWeek) {
                    RectangleMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
            GroupBox ( "Area Chart - Step count") {
                Chart(currentWeek) {
                    AreaMark(
                        x: .value("Week Day", $0.weekday, unit: .day),
                        y: .value("Step Count", $0.steps)
                    )
                }
            }
        }
    }
}

在 iOS 16 中用 SwiftUI Charts 创建一个折线图

运用 SwiftUI 图表创立的其他图表类型,显现每日步数

让折线图增加可拜访性

将图表植入 SwiftUI 的一个好处是,能够很简单地运用 可拜访性修饰符 使图表变得可拜访。为 StepCount 增加一个核算特点,将数据返回为一个字符串,可由 accessibilityLabel 运用。然后为图表中的每个标记增加可拜访性标签和值。

struct StepCount: Identifiable {
    let id = UUID()
    let weekday: Date
    let steps: Int
    init(day: String, steps: Int) {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        self.weekday = formatter.date(from: day) ?? Date.distantPast
        self.steps = steps
    }
    var weekdayString: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyyMMdd"
        dateFormatter.dateStyle = .long
        dateFormatter.timeStyle = .none
        dateFormatter.locale = Locale(identifier: "en_US")
        return  dateFormatter.string(from: weekday)
    }
}
    GroupBox ( "Line Chart - Daily Step Count") {
        Chart(currentWeek) {
            LineMark(
                x: .value("Week Day", $0.weekday, unit: .day),
                y: .value("Step Count", $0.steps)
            )
            .accessibilityLabel($0.weekdayString)
            .accessibilityValue("\($0.steps) Steps")
        }
    }

在 iOS 16 中用 SwiftUI Charts 创建一个折线图

在 SwiftUI 图表中使折线图可拜访性

为折线图增加多个数据序列

折线图是比较两个不同系列数据的好办法。创立第二个系列,即前一周的步数,并将这两个系列增加到折线图中。

let previousWeek: [StepCount] = [
    StepCount(day: "20220710", steps: 15800),
    StepCount(day: "20220711", steps: 7300),
    StepCount(day: "20220712", steps: 8200),
    StepCount(day: "20220713", steps: 25600),
    StepCount(day: "20220714", steps: 16100),
    StepCount(day: "20220715", steps: 16500),
    StepCount(day: "20220716", steps: 3200)
]
let currentWeek: [StepCount] = [
    StepCount(day: "20220717", steps: 4200),
    StepCount(day: "20220718", steps: 15000),
    StepCount(day: "20220719", steps: 2800),
    StepCount(day: "20220720", steps: 10800),
    StepCount(day: "20220721", steps: 5300),
    StepCount(day: "20220722", steps: 10400),
    StepCount(day: "20220723", steps: 4000)
]
let stepData = [
    (period: "Current Week", data: currentWeek),
    (period: "Previous Week", data: previousWeek)
]

第一次测验增加这两个系列的数据没有按预期显现。

struct LineChart2: View {
    var body: some View {
        GroupBox ( "Line Chart - Daily Step Count") {
            Chart {
                ForEach(stepData, id: \.period) {
                    ForEach($0.data) {
                        LineMark(
                            x: .value("Week Day", $0.weekday, unit: .day),
                            y: .value("Step Count", $0.steps)
                        )
                        .accessibilityLabel($0.weekdayString)
                        .accessibilityValue("\($0.steps) Steps")
                    }
                }
            }
        }
    }
}

在 iOS 16 中用 SwiftUI Charts 创建一个折线图

第一次测验在 SwiftUI Charts 中创立一个包括两个系列步数数据的折线图

显现步数系列

在折线图中显现多个根据工作日的步数系列

开始测验在折线图中显现多组数据的问题是X轴运用了日期。当时的周数紧接着上一周,所以每一个点都是沿着X轴线性递增制作的。

有必要只用工作日作为X轴的数值,这样所有的周日都在同一个X坐标上制作。

StepCount中增加另一个核算特点,以便以字符串格式返回工作日的短日。

struct StepCount: Identifiable {
    . . .
    var shortDay: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "EEE"
        return  dateFormatter.string(from: weekday)
    }
}

shortDay 用于图表中 LineMarks 的 x 值。别的,前景的款式设置为根据stepCount数组的周期。折线图运用 x 轴的工作日来显现两周的步数,以便在周之间进行比较。

struct LineChart3: View {
    var body: some View {
        VStack {
            GroupBox ( "Line Chart - Daily Step Count") {
                Chart {
                    ForEach(stepData, id: \.period) { steps in
                        ForEach(steps.data) {
                            LineMark(
                                x: .value("Week Day", $0.shortDay),
                                y: .value("Step Count", $0.steps)
                            )
                            .foregroundStyle(by: .value("Week", steps.period))
                            .accessibilityLabel($0.weekdayString)
                            .accessibilityValue("\($0.steps) Steps")
                        }
                    }
                }
                .frame(height:400)
            }
            .padding()
            Spacer()
        }
    }
}

在 iOS 16 中用 SwiftUI Charts 创建一个折线图

SwiftUI 图表中带有两个系列的步数数据的折线图

结论

在 SwiftUI Charts 中还有许多东西能够探究。运用这个结构显然比从头开端建立你自己的图表要好。

本文正在参与「金石方案 . 分割6万现金大奖」