使用 chartScrollableAxes 为 Swift Charts 图表添加滑动手势

了解如何使用 chartScrollableAxes 为你的 Swift Chart 图表添加滑动手势,这在显示大量数据时特别有用。

使用 chartScrollableAxes 为 Swift  Charts 图表添加滑动手势

使用 chartScrollableAxes 添加滑动支持

默认情况下,Chart 组件会尝试在屏幕中展示所有数据。

例如,示例代码:

var body: some View {
    VStack(alignment: .leading) {
        Text("周度销售额")
            .font(.headline)
            .padding(.leading)
        
        Chart(data) { item in
            BarMark(
                x: .value("周数", "第\(item.week)周"),
                y: .value("销售额", item.sales)
            )
            .foregroundStyle(Color.blue.gradient)
        }
        .frame(height: 300)
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 8)) { value in
                AxisValueLabel()
            }
        }
        .padding()
    }
}

当只有少量数据时,上述展示方式是可行的。但当数据量更多时,就会导致数据挤压到一起,难以阅读:

在 iOS17 上推出的 .chartScrollableAxes 修饰器,正是为了解决这个问题。通过使用这个修饰符,你可以允许用户在图表上滚动查看超出当前视图范围的数据,非常适合处理大型数据集或需要细节查看的场景。

.chartScrollableAxes 可以自动为图表添加滑动支持(横向或纵向),并且会根据数据量、标签长度自动决定每页显示多少数据。要使用它,只需要添加到 Chart 组件上即可:

var body: some View {
    VStack(alignment: .leading) {
        Text("周度销售额")
            .font(.headline)
            .padding(.leading)
        
        Chart(data) { item in
            BarMark(
                x: .value("周数", "第\(item.week)周"),
                y: .value("销售额", item.sales)
            )
            .foregroundStyle(Color.blue.gradient)
        }
        .frame(height: 300)
        .chartScrollableAxes(.horizontal) // 添加水平滚动支持
        .chartXAxis {
            AxisMarks(values: .automatic(desiredCount: 8)) { value in
                AxisValueLabel()
            }
        }
        .padding()
    }
}
0:00
/0:03

它的使用效果非常类似于 ScrollView 组件。

你可以通过设置滚动方向:

  • .horizontal(水平轴)
  • .vertical(垂直轴)
  • 甚至同时启用水平和垂直轴:  [.horizontal, .vertical]
 .chartScrollableAxes([.horizontal,.vertical]) // 添加水平滚动支持

使用 chartScrollTargetBehavior 控制滑动对齐位置

默认情况下,.chartScrollableAxes 不限制滚动停止的位置——取决于滑动的速度,可能停留在任意位置。

.chartScrollTargetBehavior 是 iOS17 上推出的另一个用于控制图表滚动行为的修饰符。它决定了当用户停止滚动时,图表的滚动位置如何调整,例如:

  • 对齐到数据点:滚动停止后,图表自动对齐到最近的数据点。
  • 分页效果:类似于分页滚动,每次滚动一个固定的距离。

.chartScrollTargetBehavior 和 ScrollView 中的 .scrollTargetBehavior 修饰器效果和使用方法都一样,我在另一篇文章中讲解过:

使用 scrollTargetBehavior 自定义 ScrollView 对齐效果
了解如何使用 iOS17 上新引入的 scrollTargetBehavior 修饰器,为你的滚动视图添加更多效果。

每次滑动固定屏幕长度(.paging)

.chartScrollTargetBehavior(.paging) 会保证每次图表滑动一个屏幕宽度的距离:

Chart(data) { item in
    BarMark(
        x: .value("周数", "第\(item.week)周"),
        y: .value("销售额", item.sales)
    )
    .foregroundStyle(Color.blue.gradient)
}
.frame(height: 300)
.chartScrollableAxes(.horizontal) // 添加水平滚动支持
.chartScrollTargetBehavior(.paging)
0:00
/0:07

每次滑动固定数量(.valueAligned)

.chartScrollTargetBehavior(.valueAligned(unit: 1)) 可以自定义设置每次滑动的 X 轴数据数量:

Chart(data) { item in
    BarMark(
        x: .value("周数", "第\(item.week)周"),
        y: .value("销售额", item.sales)
    )
    .foregroundStyle(Color.blue.gradient)
}
.frame(height: 300)
.chartScrollableAxes(.horizontal) // 添加水平滚动支持
.chartScrollTargetBehavior(.valueAligned(unit: 1))
0:00
/0:05

你可以自定义 unit 的值。

使用 chartXVisibleDomain 设置 X 轴显示数量

例如,我们可以通过设置 .chartXVisibleDomain(length: 10),使 X 轴固定显示 10 个数据:

Chart(data) { item in
    BarMark(
        x: .value("周数", "第\(item.week)周"),
        y: .value("销售额", item.sales)
    )
    .foregroundStyle(Color.blue.gradient)
}
.frame(height: 300)
.chartScrollableAxes(.horizontal) // 添加水平滚动支持
.chartXVisibleDomain(length: 10)
.chartScrollTargetBehavior(.valueAligned(unit: 1))

但是特别注意:如果你的 X 轴使用时间,默认 X 轴的单位为秒。这意味着,如果你想显示 10 天的数据,则应该设置为:

// 86400 秒 = 1 天
.chartXVisibleDomain(length: 10*86400)

否则,你的应该将会挂起或崩溃。

使用 chartScrollPosition(initialX:) 设置初始滚动位置

默认情况下,Chart 从第一项数据开始展示,就像我们之前的实例代码:

使用 chartScrollPosition(initialX:) 修饰器,你可以自定义 Chart 渲染时的初始位置:

Chart(data) { item in
    BarMark(
        x: .value("周数", "第\(item.week)周"),
        y: .value("销售额", item.sales)
    )
    .foregroundStyle(Color.blue.gradient)
}
.frame(height: 300)
.chartScrollableAxes(.horizontal) // 添加水平滚动支持
.chartScrollPosition(initialX: "第10周") // 设置初始滚动位置为第22周
.chartScrollTargetBehavior(.valueAligned(unit: 1))
初始显示为第 10 周,而不是第 1 周。用户仍然可以左右滑动。

这非常适合用来展示以日期作为 X 轴的数据。例如,如果要展示之前一年到之后一年的计划,你可以将初始位置设置在今天,而不是一年前。