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.
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.
Nowadays, state is mutable. So just set the state to .cancelled and the gesture will be cancelled. The headers suggest that it is still a get-only property, but in practice, it actually is mutable. They must have included the import of UIKit.UIGestureRecognizer (discussed below) as part of the broader import UIKit.
In previous iOS versions, state was immutable and one had explicitly import the gesture recognizer header to make gestures cancelable:
import UIKit.UIGestureRecognizer
That would make the otherwise immutable state property a readwrite property. But this is no longer necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With