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) } }
关键改动说明
新增状态变量:
isBeyondMax:明确记录当前拖拽是否处于分钟上限外,避免依赖lastDragAmount的波动判断hasTriggeredHourChange:标记单次手势内是否已完成过小时增减,确保同一方向跨越边界仅触发一次
修正边界判断逻辑:
- 从上限内拖拽到上限外时,仅在
!isBeyondMax && !hasTriggeredHourChange条件满足时递增小时,并标记已触发 - 从上限外拖拽回上限内时,仅在
isBeyondMax && !hasTriggeredHourChange条件满足时递减小时,并标记已触发
- 从上限内拖拽到上限外时,仅在
手势结束重置状态:
- 在
onEnded回调中重置isBeyondMax和hasTriggeredHourChange,确保下一次手势不受上一次状态影响
- 在
这样就能严格实现你预期的功能:向上拖拽到分钟满59后继续拖拽,小时加1分钟归0;同一手势向下拖拽回分钟范围内,小时减1分钟从59开始递减;重复跨边界操作时均单次触发小时变化。
内容的提问来源于stack exchange,提问作者nielsK
相关产品推荐
相关产品推荐

