SwiftUI - 长按手势增加数字,然后在释放手势后停止

Jim*_*ton 1 timer swift swiftui

我正在尝试创建一个步进器,其中数字在长按手势时快速增加,并在用户释放时停止。

到目前为止,我已经在长按上获得了增量,但是当我释放计时器时,计时器仍然继续,继续增加状态。

我该如何解决当用户松开按键时计时器停止的问题。

struct CustomFoodItemView: View {
    @State var foodName = ""
    @State var proteinAmount = 1
    @State var carbAmount = 1
    @State var fatAmount = 1
    
    @State private var timer: Timer?
    @State var isLongPressing = false
    
    var body: some View {
        VStack{
            
            VStack{
                Text("Food Name")
                TextField("", text: $foodName)
                    .multilineTextAlignment(.center)
                    .border(.white)
                    .padding(.trailing, 10)
                    .frame(width:100, height:10)
            }
            HStack{
                Text(String(proteinAmount) + "g")
                    .frame(width:50, height:50)
                
                Image(systemName: "plus.circle.fill")
                    .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 30, height: 30)
                        .foregroundColor(Color("SuccessButtonColor"))
                        .simultaneousGesture(LongPressGesture(minimumDuration: 0.2).onChanged { _ in
                                      print("long press")
                                      self.isLongPressing = true
                            if self.isLongPressing == true{
                                self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
                                    proteinAmount += 1
                                })
                            } 
                                  }
                                .onEnded { _ in
                            print("stopped") //why won't you stop
                                    self.isLongPressing = false
                                })
                       }
              }
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Seb*_*Fox 6

两件事情:

  1. 你根本不停止计时器,要停止它,你必须使其无效(正如 Leo 提到的)。你可以用 来做到这一点self.timer?.invalidate()
  2. 当LongPressGesture.onEndedLongPressGesture识别为按下按钮时间超过minimumDuration时间时,将调用该方法,它不处理按钮释放时的事件。所以你不想停止计时器.onEnded

组合的 LongPressGesture 和 DragGesture

我尝试了您的代码,一种方法可能是使用LongPressGesture来启动计时器,并DragGesture使用最小距离 0 来识别按钮释放。

这看起来像:

struct CustomFoodItemView: View {
    @State var foodName = ""
    @State var proteinAmount = 0
    @State var carbAmount = 0
    @State var fatAmount = 0
    let maxValue = 50
    let minValue = 0
    
    @State private var timer: Timer?
    
    var body: some View {
        
        // a drag gesture that recognizes the release of the button to stop the timer, set minimumDistance to 0 to ensure no dragging is required
        let releaseGesture = DragGesture(minimumDistance: 0)
            .onEnded { _ in
                self.timer?.invalidate()
                print("Timer stopped")
            }
        
        // a long press gesture to activate timer and start increasing the proteinAmount
        let longPressGestureIncrease = LongPressGesture(minimumDuration: 0.2)
            .onEnded { value in
                self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
                    if proteinAmount < maxValue {
                        proteinAmount += 1
                    }
                })
                print("Timer started")
            }


        // a long press gesture to activate timer and start decreasing the proteinAmount
        let longPressGestureDecrease = LongPressGesture(minimumDuration: 0.2)
            .onEnded { value in
                self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
                    if proteinAmount > minValue {
                        proteinAmount -= 1
                    }
                })
                print("Timer started")
            }
    
        // a combined gesture that forces the user to long press before releasing for increasing the value
        let combinedIncrease = longPressGestureIncrease.sequenced(before: releaseGesture)
    
        // a combined gesture that forces the user to long press before releasing for decreasing the value
        let combinedDecrease = longPressGestureDecrease.sequenced(before: releaseGesture)
        
        VStack{
            
            VStack{
                Text("Food Name")
                TextField("", text: $foodName)
                    .multilineTextAlignment(.center)
                    .border(.white)
                    .padding(.trailing, 10)
                    .frame(width:100, height:10)
            }
            HStack{
                Image(systemName: "minus.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 30, height: 30)
                    .foregroundColor(.red)
                    .gesture(combinedDecrease)

                Text(String(proteinAmount) + "g")
                    .frame(width:50, height:50)
                
                Image(systemName: "plus.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 30, height: 30)
                    .foregroundColor(.red)
                    .gesture(combinedIncrease)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请查看包含代码片段中的几个项目的 gif(开始长按后数字增加,释放“+”按钮时停止):

通过激活的计时器增加数量

通过激活计时器增加和减少数量