iosswiftuigesturerecognizer

How to cancel LongPressGestureRecognizer?


I have a view that has a LongPressGestureRecognizer assigned to it which calls the following method:

@IBAction func longPressOnView1Recognized(_ sender: UIGestureRecognizer) {

    if sender.state == .began {
        // this runs when user's finger is down a "long time"
    }
    if sender.state == .ended {
        // this runs when user's finger goes up again after the .began state 
    }

}

This all works as expected, but I'm trying to find a (good/proper) way of being able to programmatically cancel the long press recognizer (in certain circumstances) while the user's finger is still down.

That is, while a user's finger is still down on the view, and the recognizer has entered the .began state, (but before the user has lifted their finger -- before recognizer enters the .ended state)... is there some code we can run that will prevent the method above from firing when the user lifts their finger... like prematurely telling IOS to no longer listen for UP events for the remainder of this gesture?

I've read these docs, but I don't have that much experience with IOS touch, and I can't seem to find any method that is designed for this purpose.

my GestureRecognizer.reset() does not seem to do what I'm describing.

I can think of two possibilities:

1) A boolean flag, that would go inside the if sender.state == .ended {} closure

2) this:

myLongPressRecognizer.isEnabled = false
myLongPressRecognizer.isEnabled = true

Both of these work but seem not so great.


Solution

  • You are all good with disabling and reenabling the gesture recognizer so doing

    myLongPressRecognizer.isEnabled = false
    myLongPressRecognizer.isEnabled = true
    

    is completely correct.

    What I am worried about is you don't completely understand gesture recognizers. You should always use switch statement when handling gesture recognizer. Check the comments:

    func handleLongPressGestureRecognizer(_ sender: UIGestureRecognizer) {
    
        switch sender.state {
        case .began:
            // This will be called only once when the gesture starts
            print("Long press did begin at \(sender.location(in: sender.view))")
        case .changed:
            // This will be called whenever your finger moves (at some frequency obviously).
            // At this point your long press gesture is acting exactly the same as pan gesture
            print("Long press changed position to \(sender.location(in: sender.view))")
        case .ended:
            // This is when user lifts his finger assuming the gesture was not canceled
            print("Long press ended at \(sender.location(in: sender.view))")
        case .cancelled:
            // This is equally important as .ended case. You gesture may be canceled for many reasons like a system gesture overriding it. Make sure to implement logic here as well.
            print("Long press canceled at \(sender.location(in: sender.view))")
        case .failed, .possible:
            // These 2 have been added additionally at some point. Useless as far I am concerned.
            break
        }
    
    }
    

    So at least you should handle cancelled status. But also note that the changed status will be triggered whenever the gesture is moved.