Home > Net >  SwiftUI: Longpress Gesture Hold for only 1 Second
SwiftUI: Longpress Gesture Hold for only 1 Second

Time:01-04

Using the Long press gestures on SwiftUI only keep the long press hold gesture for 1 second then automatically releases the long press. I would like for the user to press up to 1 minute or more. Is this possible and how can it be done.

Check out my code below, which currently only supports a 1-second duration long-press gesture.

    struct IgnitionDriveView: View {
    
    @GestureState private var drivingGestureState = false
    @GestureState private var reverseGestureState = false
    @State private var showDriveAlert = true
    @State private var showOutOfGasAlert = false
    @State var distanceCovered: Float = 1.0
    
    var body: some View {
        
        let circleShape = Circle()
        let driveGesture = LongPressGesture(minimumDuration: 1)
            .updating($drivingGestureState) { (currentState, gestureState, transaction) in
                gestureState = currentState
            }.onChanged { _ in
                if distanceCovered < 1000 {
                    self.distanceCovered  = 10
                } else {
                    showOutOfGasAlert = true
                }
            }
        
        let reverseGesture = LongPressGesture(minimumDuration: 1)
            .updating($reverseGestureState) { (currentState, gestureState, transaction) in
                gestureState = currentState
            }.onChanged { _ in
                if distanceCovered > 0 {
                    self.distanceCovered -= 10
                }
            }
        
        VStack(alignment: .leading) {
            Text("Distance Covered in Km: \(distanceCovered)")
                .font(.headline)
            ProgressView(value: distanceCovered > 0 ? distanceCovered : 0, total: 1000)
                .frame(height: 40)
            
            HStack {
                ZStack {
                    circleShape.strokeBorder(style: StrokeStyle(lineWidth: 2))

                    circleShape
                        .fill(drivingGestureState ? .white : .red)
                        .frame(width: 100, height: 100, alignment: .center)
                    
                    Text("D")
                        .bold()
                        .padding()
                        .foregroundColor(.green)
                        .font(.title)
                }.foregroundColor(.green)
                    .gesture(driveGesture)
                
                Spacer()
                
                ZStack {
                    circleShape.strokeBorder(style: StrokeStyle(lineWidth: 2))

                    circleShape
                        .fill(reverseGestureState ? .white : .red)
                        .frame(width: 100, height: 100, alignment: .center)
                    
                    Text("R")
                        .bold()
                        .padding()
                        .foregroundColor(.red)
                        .font(.title)
                }.foregroundColor(.green)
                    .gesture(reverseGesture)
                    
            }.padding()
        }.alert("Press D to Drive and R to Reverse", isPresented: $showDriveAlert) {
            Button("Okay") { showDriveAlert = false }
        }.alert("You ran out of Gas, Reverse to Gas Station", isPresented: $showOutOfGasAlert) {
            Button("Sucks, but fine!") { showOutOfGasAlert = false }
        }
        .padding()
    }
}

Screenshot

CodePudding user response:

The LongPressGesture is updating after the minimum time no matter if the user lifts its finger or not. Take a look here on how to register to the onEnded even which I guess is what you want to wait for. i.e when the user takes his/hers finger off screen - https://developer.apple.com/documentation/swiftui/longpressgesture

CodePudding user response:

here is a very basic approach that you can build on, based on the code in:

https://adampaxton.com/make-a-press-and-hold-fast-forward-button-in-swiftui/

struct IgnitionDriveView: View {
    
    @State private var timer: Timer?
    @State var isLongPressing = false
    
    @State private var showDriveAlert = true
    @State private var showOutOfGasAlert = false
    @State var distanceCovered: Float = 0.0
    
    var body: some View {
        
        let circleShape = Button(action: {
            if isLongPressing {
                isLongPressing.toggle()
                timer?.invalidate()
            }
        }) {
            Circle()
               .strokeBorder(style: StrokeStyle(lineWidth: 2))
               .frame(width: 100, height: 100, alignment: .center)
        }
        
        VStack(alignment: .leading) {
            Text("Distance Covered in Km: \(distanceCovered)").font(.headline)
            ProgressView(value: distanceCovered > 0 ? distanceCovered : 0, total: 1000).frame(height: 40)
            
            HStack {
                ZStack {
                    circleShape
                    .simultaneousGesture(LongPressGesture(minimumDuration: 0.2).onEnded { _ in
                        isLongPressing = true
                        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
                            if distanceCovered < 1000 {
                                distanceCovered  = 10
                            } else {
                                showOutOfGasAlert = true
                            }
                        })
                    })
                    
                    Text("D")
                        .bold()
                        .padding()
                        .foregroundColor(.green)
                        .font(.title)
                }.foregroundColor(.green)
                
                Spacer()
                
                ZStack {
                    circleShape
                    .simultaneousGesture(LongPressGesture(minimumDuration: 0.2).onEnded { _ in
                        isLongPressing = true
                        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
                            if distanceCovered > 0 {
                                distanceCovered -= 10
                            }
                        })
                    })
                    
                    Text("R")
                        .bold()
                        .padding()
                        .foregroundColor(.red)
                        .font(.title)
                }.foregroundColor(.green)
                
            }.padding()
        }.alert("Press D to Drive and R to Reverse", isPresented: $showDriveAlert) {
            Button("Okay") { showDriveAlert = false }
        }.alert("You ran out of Gas, Reverse to Gas Station", isPresented: $showOutOfGasAlert) {
            Button("Sucks, but fine!") { showOutOfGasAlert = false }
        }
        .padding()
    }
}
  •  Tags:  
  • Related