You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加自定义DragGesture时如何保留SwiftUI Chart原生横向滚动

解决SwiftUI Chart自定义拖拽后横向滚动失效的问题

你的问题出在自定义的DragGesture拦截了Chart原生的滚动手势——哪怕用了simultaneousGesture也没用,因为你设置了minimumDistance: 0,这个手势会捕获所有触摸事件,直接覆盖了Chart的滚动逻辑。

其实根本不需要自己写拖拽手势,利用Chart自带的chartXSelection就能实现「拖拽结束后选中状态不重置」的需求,还能完整保留原生滚动功能,具体修改步骤如下:

  1. 在SleepScoreChart里新增一个本地状态变量,用来接收Chart原生的选中值:
@State private var tempSelectedDate: Date?
  1. 把原来绑定rawSelectedDate的chartXSelection改成绑定这个本地变量,再通过onChange监听本地变量的变化,只在它有值时才更新rawSelectedDate:
.chartXSelection(value: $tempSelectedDate)
.onChange(of: tempSelectedDate) { newDate in
    // 仅在选中有效日期时更新绑定值,拖拽结束后tempSelectedDate会变为nil,不会影响rawSelectedDate
    if let newDate {
        rawSelectedDate = newDate
    }
}
  1. 删除掉原来的.chartOverlay和里面的自定义拖拽手势逻辑。

修改后的完整代码:

struct ScoreChartModel: Identifiable {
    let id = UUID()
    var score: Int
    var date: Date
}

struct SleepScoreChart: View {
    @State var chartDisplayData: [ScoreChartModel]
    @Binding var rawSelectedDate: Date?
    @State private var tempSelectedDate: Date? // 新增本地状态
    
    var body: some View {
        Chart {
            ForEach(chartDisplayData) { chartData in
                PointMark(
                    x: .value("sleep date", chartData.date, unit: .day),
                    y: .value("sleep score", chartData.score)
                )
                .interpolationMethod(.catmullRom)
            }
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .day)) { _ in
                AxisTick()
                AxisGridLine()
                AxisValueLabel(format: .dateTime.weekday(.abbreviated))
            }
        }
        .chartYScale(domain: 0...120)
        .chartYAxis(.hidden)
        .chartScrollableAxes(.horizontal)
        .chartXVisibleDomain(length: 3600 * 24 * 7)
        .chartXSelection(value: $tempSelectedDate) // 绑定本地变量
        .onChange(of: tempSelectedDate) { newDate in // 监听变化更新绑定值
            if let newDate {
                rawSelectedDate = newDate
            }
        }
        .chartScrollPosition(initialX: Date())
    }
}

这样修改后,既保留了Chart原生的横向滚动功能,又能实现拖拽选择数据点后rawSelectedDate不会被重置的需求——原生的chartXSelection在拖拽结束后会把tempSelectedDate设为nil,但我们只在它有值的时候更新rawSelectedDate,所以绑定值会一直保留最后选中的日期。

内容的提问来源于stack exchange,提问作者Michał Tomys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:25:19