使用 chartXSelection 为 Swift Charts 添加交互功能

了解如何使用 chartXSelection 为 Swift Charts 添加交互功能。

使用 chartXSelection 为 Swift Charts 添加交互功能

在 iOS 17 中,Apple 为 SwiftUI 的 Charts 框架引入了新的 .chartXSelection 修饰器。这个修饰器的主要用途是允许开发者在图表中捕获用户对 X 轴数据的选择,从而实现更丰富的交互功能。

chartXSelection 使用场景

例如,我们有如下示例代码:

var body: some View {
    VStack(alignment: .leading) {
        Text("周度销售额")
            .font(.headline)
            .padding(.leading)

        Chart(data) { item in
            LineMark(
                x: .value("周数", "第\(item.week)周"),
                y: .value("销售额", item.sales)
            )
            .foregroundStyle(Color.blue.gradient)
        }
        .frame(height: 300)
        .chartScrollableAxes(.horizontal)
        .chartScrollPosition(initialX: "第10周")
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 8)) { value in
                AxisValueLabel()
            }
        }
        .padding()
    }
}

上述代码创建了一个常规的折线图,并使用 chartScrollableAxes 修饰器添加了横向滑动功能:

上面这个图表很简洁的,但无法获取到每周具体的销售额。为了让图表功能更加完善,我们可以增加:当用户点击某个数据时,能显示该数据更具体的注释信息,类似 Apple 健康应用中的效果:

为了实现上述功能,就需要使用到 chartXSelection 修饰器。

使用 chartXSelection 修饰器

添加垂直标尺标注

chartXSelection 修饰器可用于在用户与图表交互时,获取他们在 X 轴上的选择位置。通过绑定(Binding)的方式,chartXSelection 可以实时获取和设置选中的值,同时支持点击和拖动操作。

为了实现类似上述效果,我们需要做以下工作:

1. 定义选中数据的状态变量

首先,创建两个 @State 变量,用于保存 chartXSelection 返回的选中数据:

@State private var selectedWeek: String?
@State private var selectedSales: Double?

2. 在图表中应用 chartXSelection

chartXSelection 本身仅用于获取数据,不会自动更新 UI。因此,需要手动添加 RuleMark,用于显示选中时的垂直标尺标注。

实例代码:

@State private var selectedWeek: String?
@State private var selectedSales: Double?

var body: some View {
    VStack(alignment: .leading) {
        Text("周度销售额")
            .font(.headline)
            .padding(.leading)

        Chart(data) { item in
            LineMark(
                x: .value("周数", "第\(item.week)周"),
                y: .value("销售额", item.sales)
            )
            .foregroundStyle(Color.blue.gradient)

            if let week = selectedWeek,
                "第\(item.week)周" == week
            {
                RuleMark(
                    x: .value("选中周", "第\(item.week)周")
                )
                .foregroundStyle(.gray.opacity(0.3))
                .lineStyle(StrokeStyle(lineWidth: 2))
            }
        }
        .frame(height: 300)
        .chartScrollableAxes(.horizontal)
        .chartScrollPosition(initialX: "第10周")
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 8)) { value in
                AxisValueLabel()
            }
        }
        .chartXSelection(value: $selectedWeek)
        .padding()
    }
}

添加注释框

为了更直观地显示选中信息,可以使用 PointMark 搭配 .annotation 添加数据标注: