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

SwiftUI拖拽手势控制计时器:整数增减限制逻辑异常求助

问题分析

你的核心问题在于仅通过lastDragAmount判断是否跨上限,但拖拽过程中该值会持续更新,且未明确跟踪当前状态(是否处于上限外),导致边界判断逻辑出现误触发,比如超过上限后继续拖拽时小时持续递增。

解决方案

我们需要添加状态变量明确跟踪当前是否处于上限外,以及在单次手势内是否已经完成过跨边界的小时增减操作,确保每次跨越边界仅触发一次小时变化。

以下是修正后的完整代码:

struct JoystickView: View {
    @Binding var minutes: Int
    @Binding var hours: Int
    @GestureState private var dragState = DragState.inactive
    
    // 跟踪当前是否处于上限外(dragAmount > 1)
    @State private var isBeyondMax = false
    // 标记单次手势内是否已完成过小时递增/递减操作
    @State private var hasTriggeredHourChange = false

    var body: some View {
        GeometryReader { geometry in
            Circle()
                .fill(Color.orange)
                .frame(width: 80 + (dragState.isActive ? geometry.size.height * abs(dragState.dragOffset.height / geometry.size.height) : 0),
                       height: 80 + (dragState.isActive ? geometry.size.height * abs(dragState.dragOffset.height / geometry.size.height) : 0))
                .position(x: geometry.size.width / 2, y: geometry.size.height * 0.8)
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .updating($dragState) { value, state, transaction in
                            state = DragState(isActive: true, dragOffset: value.translation)
                            let dragAmount = abs(value.translation.height / geometry.size.height)
                            
                            // 情况1:当前拖拽在分钟范围内(<=1)
                            if dragAmount <= 1 {
                                minutes = Int(dragAmount * 59)
                                
                                // 之前处于上限外,且未触发过小时递减
                                if isBeyondMax && !hasTriggeredHourChange {
                                    hours -= 1
                                    hasTriggeredHourChange = true
                                }
                                // 更新状态:回到上限内
                                isBeyondMax = false
                            } 
                            // 情况2:当前拖拽超过分钟上限(>1)
                            else {
                                minutes = 0
                                
                                // 之前处于上限内,且未触发过小时递增
                                if !isBeyondMax && !hasTriggeredHourChange {
                                    hours += 1
                                    hasTriggeredHourChange = true
                                }
                                // 更新状态:进入上限外
                                isBeyondMax = true
                            }
                        }
                        .onEnded { _ in
                            // 手势结束后重置状态,为下一次手势做准备
                            isBeyondMax = false
                            hasTriggeredHourChange = false
                        }
                )
        }
        .frame(maxHeight: .infinity)
    }
}

struct DragState {
    var isActive: Bool = false
    var dragOffset: CGSize = .zero
    var hasExceededMaxLimit: Bool = false

    static let inactive = DragState(isActive: false)
}

struct TimerView: View {
    var hours: Int
    var minutes: Int

    var body: some View {
        Text(String(format: "%02d:%02d", hours, minutes))
            .foregroundColor(.white)
            .font(.system(size: 100))
            .frame(maxHeight: UIScreen.main.bounds.height / 3)
    }
}
关键改动说明
  1. 新增状态变量:

    • isBeyondMax:明确记录当前拖拽是否处于分钟上限外,避免依赖lastDragAmount的波动判断
    • hasTriggeredHourChange:标记单次手势内是否已完成过小时增减,确保同一方向跨越边界仅触发一次
  2. 修正边界判断逻辑:

    • 从上限内拖拽到上限外时,仅在!isBeyondMax && !hasTriggeredHourChange条件满足时递增小时,并标记已触发
    • 从上限外拖拽回上限内时,仅在isBeyondMax && !hasTriggeredHourChange条件满足时递减小时,并标记已触发
  3. 手势结束重置状态:

    • 在onEnded回调中重置isBeyondMax和hasTriggeredHourChange,确保下一次手势不受上一次状态影响

这样就能严格实现你预期的功能:向上拖拽到分钟满59后继续拖拽,小时加1分钟归0;同一手势向下拖拽回分钟范围内,小时减1分钟从59开始递减;重复跨边界操作时均单次触发小时变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:35:39