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

SwiftUI中如何通过DragGesture实现计数器单次增减并复位视图?

如何通过DragGesture实现单次触发的计数器增减

当然可以实现!你的核心问题是onChanged会在拖动过程中持续触发,导致计数器被反复修改——哪怕你重置了offset,后续的onChanged依然会因为手指移动更新位移值,再次触发计数逻辑。

我们只需要添加一个触发状态标记来避免单次拖动中的重复触发,下面是修正后的完整代码和思路:

问题分析

你的初始代码中,onChanged会在手指拖动的每一个时刻被调用,只要offset超过阈值就会修改count。即使你在触发后重置offset,下一次onChanged还是会把offset设置为当前的拖动位移,导致阈值判断被反复触发,计数器持续变化。

解决方案

添加一个@State变量hasTriggered,用来记录本次拖动是否已经完成过计数操作:

  • 拖动过程中,只有当hasTriggered为false时才响应拖动位移和阈值判断
  • 当达到阈值且未触发过时,修改计数器,标记hasTriggered为true,同时复位offset
  • 拖动结束时,重置hasTriggered为false,确保下次拖动可以正常触发

修正后的代码

struct ContentView: View {
    @State private var count: Int = 0
    @State private var offset: CGSize = .zero
    // 新增:标记本次拖动是否已触发计数
    @State private var hasTriggered: Bool = false
    
    var body: some View {
        VStack(spacing: 15) {
            Text("\(count)")
                .font(.largeTitle)
                .fontWeight(.bold)
            
            RoundedRectangle(cornerRadius: 10)
                .frame(width: 250, height: 350)
                .foregroundColor(.white)
                .shadow(color: .black.opacity(0.3), radius: 10)
                .offset(x: offset.width)
                .gesture(DragGesture()
                    .onChanged { value in
                        withAnimation(.spring()) {
                            // 只有未触发过计数时,才响应拖动操作
                            guard !hasTriggered else { return }
                            
                            offset = value.translation
                            
                            // 右滑超过阈值,计数+1并锁定触发状态
                            if offset.width > 150 {
                                count += 1
                                hasTriggered = true
                                offset = .zero
                            } 
                            // 左滑超过阈值,计数-1并锁定触发状态
                            else if offset.width < -150 {
                                count -= 1
                                hasTriggered = true
                                offset = .zero
                            }
                        }
                    }
                    .onEnded { _ in
                        withAnimation(.spring()) {
                            offset = .zero
                        }
                        // 重置触发状态,允许下次拖动触发计数
                        hasTriggered = false
                    })
        }
        .padding()
        .background(Color.gray.opacity(0.1))
        .edgesIgnoringSafeArea(.all)
    }
}

效果说明

现在当你拖动矩形超过左右150的阈值时:

  1. 计数器立刻增减1次
  2. 矩形会立刻复位到初始位置
  3. 本次拖动过程中,即使继续移动手指,也不会再触发计数
  4. 松开手指后,触发状态自动重置,下次拖动可以再次正常触发计数

内容的提问来源于stack exchange,提问作者Milez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:07:41