May I know what exactly requireGestureRecognizerToFail will do? - ios

Can any one let me know what exactly the below code line will do? I have referred Apples documentation but didn't get the exact picture about this,
[scrollview.panGestureRecognizer requireGestureRecognizerToFail:swipeRightGesture];

When user make a right swipe gesture then pan gesture will be failed (ignored).

An example,[_singleTap requireGestureRecognizerToFail:_doubleTap], when you want a single-tap gesture require that a double-tap gesture fail. Double-tap includes two single taps, so if no requireGestureRecognizerToFail single-tap gesture delegate method may invoke twice.
So here, swipe gesture may trigger pan gesture, then will invoke panGestureRecognizer delegate method while you are swiping actually.
If add [panGestureRecognizer requireGestureRecognizerToFail:swipeRightGesture] , once swipeRightGesture transitions to UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan, panGestureRecognizer transitions to UIGestureRecognizerStateFailed immediately.
And only swipeRightGesture haven't transited to above RecognizerStates, there is possible for panGestureRecognizer to respond, transited to UIGestureRecognizerStateBegan, and invoke panGestureRecognizer delegate method.

The accepted answer is only partially correct...
According to the docs for requireGestureRecognizerToFail:
The state that the receiver transitions to depends on what happens
with otherGestureRecognizer [the second referenced gesture recognizer]:
If otherGestureRecognizer transitions to UIGestureRecognizerStateFailed, the receiver transitions to its normal
next state.
If otherGestureRecognizer transitions to UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan,
the receiver transitions to UIGestureRecognizerStateFailed.
This means that in the following code:
[scrollview.panGestureRecognizer requireGestureRecognizerToFail:swipeRightGesture];
When the user makes a swipe gesture, the pan gesture will only fail if that swipe gesture proceeds as normal. If that swipe gesture fails however, the pan gesture will proceed instead.

Related

Why and how does UIPanGestureRecognizer mute UISwipeGestureRecognizer while UITapGestureRecognizers don't mute each other by default?

In the doc Coordinating Multiple Gesture Recognizers, it says:
UIKit normally allows the recognition of only one gesture at a time on
a single view. ... For example, in a view that contains both pan and swipe gesture recognizers, swipes are never recognized.
With that being said, there are also some exceptions. For example, in a view with two UITapGestureRecognizers, the actions of both will get fired.
There's the UIGestureRecognizerDelegate method gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) comes into play externally. But how can the system built-in gesture recognizers, such as UITapGestureRecognizer, decide internally whether or not to work with other recognizers? Or, is there any difference between continuous gesture recognizers and discrete gesture recognizers as regards the behavior?
There are two interesting methods of UIGestureRecognizer in the decision process, in which gesture recognizers may be "prevented":
canPrevent(_:)
canBePrevented(by:)
By debugging subclasses of UITapGestureRecognizer, UISwipeGestureRecognizer and UIPanGestureRecognizer, I found that:
A "double tap" recognizer will prevent a "single tap" recognizer, but NOT vice versa
A pan recognizer will prevent a swipe recognizer
When there are multiple gesture recognizers, the first one that recognizes its gesture will render other recognizers into .failed, by default.
That explains the observed behavior.

Executing pan gesture recognizer ONLY after long press recognizer has fired

I'm trying to implement a drag and drop UI for my UIView using the pan gesture recognizer. I have that piece of code working, but now I want to only execute the drag and drop logic only AFTER the user has long pressed on my to-be-dragged view.
I'm implementing the code in the below question
Recognize long press and pan gesture recognizers together but it's not exactly what I want. Any idea?
Set up your view controller as the delegate of the pan gesture recognizer.
Implement the gestureRecognizerShouldBegin(_:) method. Return false until after the long press gesture recognizer fires.
Found another post whose title was a bit misleading so I didn't look into it too much the first time.
Combine longpress gesture and drag gesture together
It turns out, UILongPressGesture already can help me achieve the drag and drop effect that I want. That means I do NOT need the UIPanGesture at all. I just used selector/handler for the pan gesture for the long press gesture. Except the long press gesture doesn't have the translation properties, so I use
myView.center = sender.location(in: myView.superview)
to achieve the same dragging effect.

Using Swipe Gesture and Touches Began/Moved/Ended at the same time

I'm trying to use a swipe gesture along with some logic in touches began/moved/ended. Ideally, it would be good if:
User swipes left/right, touches began/moved/ended logic is not called (or cancelled).
For all other cases, touches began/moved/ended logic is called as usual.
Is this possible?
I tried adding the following (based on process both touch event and gesture recognizer) but touches moved/ended is still called:
leftSwipeGestureRecognizer.delaysTouchesBegan = true
self.leftSwipeGestureRecognizer.cancelsTouchesInView = false
Should be:
self.leftSwipeGestureRecognizer.cancelsTouchesInView = YES
This mean: touches are cancelled in case gesture was recognized, otherwise, touches began/moved/ended called.
From documentation:
When this property is YES (the default) and the receiver recognizes
its gesture, the touches of that gesture that are pending are not
delivered to the view and previously delivered touches are cancelled
through a touchesCancelled:withEvent: message sent to the view. If a
gesture recognizer doesn’t recognize its gesture or if the value of
this property is NO, the view receives all touches in the multi-touch
sequence.
In this case I would create a custom UIGestureRecognizer for a new behaviour in touches began/moved/ended. Useful link here. Than I would set delegate for both swipe and custome recognizers and implement gestureRecognizer:shouldRequireFailureOfGestureRecognizer: method to fulfill requirements. Link to documentation.

How to cancel LongPressGesture so PanGesture can recognise

I working with UIGestureRecognizer atm creating some map alike program.
My work require me to listen to both long press gesture and pan gesture separate, so each of them can do their own task.
But in one case, i need to listen to long press first to know which object is chosen. After that, when i begin to move my finger (without lift it up), that object will be move too. It kind of like drag a marker around in google map. But because my long press recognizer already fired, pan gesture recognizer didn't get fire until i tab on the screen again.
I tried something like
recognizer.enabled = NO;
recignizer.enabled = YES;
But it didn't help at all.
So i wonder if there anyway to cancel long press after it recognized (UIGestureRecognizerStateBegan) so pan gesture recognizer will be fire immediately when i begin to move. Or i have to use UIResponder to make it work ?
Thank for your advice.
You can actually use UILongPressGestureRecognizer to detect the pan gesture after the long tap. The only caveat is that, since UILongPressGestureRecognizer is a subclass of UIGestureRecognizer it does not have the -translationInView: that is so handy in UIPanGestureRecognizer.
You can anyway do these calculations on your own by keeping track of where the touch has moved after the long press, as it will keep firing the action bound to the gesture recognizer.
Take a look at this question, it may help to calculate the translation with the long press gesture.

iOS UIGestureRecognizer

I have two questions:
Can I implement gesture recogniser that inherits from UISwipeGestureRecognizer and add logic to the UIEvent handlers?
Can I implement UIGestureRecognizer without attaching it to a UIView? Meaning, I will analyze and manage the UIEvent events and call the proper selector (touchesBegan, touchesMoved, touchesEnded, touchesCancelled)?
In the meantime I have problems reseting the gesture recogniser when the state is UIGestureRecognizerStateEnded.
You asked:
Can I implement gesture recogniser that inherits from UISwipeGestureRecognizer and add logic to the UIEvent handlers?
Yes. See Creating a Custom Gesture Recognizer in the Event Handling Guide for iOS. Also see WWDC 2010 session 121 - Advanced Gesture Recognition. It probably depends upon what you want to do, though, and you should see if you can accomplish what you want by configuring the standard swipe gesture's direction and numberOfTouches parameters. I've done more subclassing on continuous gestures like UIPanGestureRecognizer, but I see no reason why you couldn't do it on a swipe, too.
Can I implement UIGestureRecognizer without attaching it to a UIView? Meaning, I will analyze and manage the UIEvent events and call the proper selector (touchesBegan, touchesMoved, touchesEnded, touchesCancelled)?
No. Obviously you can create one, but it just won't receive any of the events until it's added to a UIView and that view receives touches.
In the meantime I have problems reseting the gesture recogniser when the state is UIGestureRecognizerStateEnded.
You'd have to submit a new question providing a relevant code snippet for us to help you on that one. In general, you'd do any post-gesture cleanup when your handler is called for UIGestureRecognizerStateEnded (and UIGestureRecognizerStateCancelled or UIGestureRecognizerStateFailed) and you'd initialize everything for the next gesture when you receive the next UIGestureRecognizerStateBegan.

Resources