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

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.

Related

Is UIPanGestureRecognizer discrete or continuous?

I find this doc a bit confusing:
https://developer.apple.com/documentation/uikit/uipangesturerecognizer
Specifically, the top of the doc says it's discrete:
A discrete gesture recognizer that interprets panning gestures.
Then the following description says:
A panning gesture is continuous. It begins (UIGestureRecognizer.State.began) when the user moves the minimum number of fingers allowed (minimumNumberOfTouches) enough distance for recognition as a pan. It changes (UIGestureRecognizer.State.changed) when the user moves a finger while pressing with the minimum number of fingers. It ends (UIGestureRecognizer.State.ended) when the user lifts all fingers.
So which is it? discrete or continuous?
My understanding is that discrete recognizer only calls callback action only when it's recognized (e.g. Swipe), but continuous recnogizers calls the callback action when it's moved as well. So pan gesture should be continuous. Am i right?
From the first link DonMag posts in his answer, About the Gesture Recognizer State Machine,
It explains that discrete gesture recognizers fire/fail once, then reset. Continuous gesture recognizers can go into a loop, returning a state of UIGestureRecognizer.State.changed as the user moves their finger.
Edit:
I think #OMGPOP figured out what's going on. It looks like The word "discrete" in the sentence "A discrete gesture recognizer that interprets panning gestures" should be "concrete". That must be a typo.
Supporting that idea is the fact that the description of the base UIGestureRecognizer class says "UIGestureRecognizer: The base class for concrete gesture recognizers." The UIGestureRecognizer is the abstract parent class of concrete classes like UIPanGestureRecognizer.
It seems to me this is mainly a "terminology" thing.
A UIPanGestureRecognizer is discreet in that it doesn't begin on touch... it enters a state of "possible." It only generates a .began event after the touch has moved enough distance for it to be recognized as a Pan. After that, it is continuous as it sends .changed events as the touch is moved.
You may find it helpful to review these Apple's docs (among others):
About the Gesture Recognizer State Machine
Implementing a Custom Gesture Recognizer
Implementing a Discrete Gesture Recognizer
Implementing a Continuous Gesture Recognizer
Although... you probably only need to know the "down-and-dirty" if you are, in fact, implementing your own gesture recognizer.

How many types of gesture does IOS Support

How many type of gesture that ios can recognize and we can work on occurring that gesture.
Language Swift / Objective C
Platform Xcode
There are seven type of gesture that support in ios.
Tap Gesture Recognizer
Pinch Gesture Recognizer
Rotation Gesture Recognizer
Swipe Gesture Recognizer
Pan Gesture Recognizer
Screen Edge Pan Gesture Recognizer
Long Press
Basically it comes down to Gesture Recogniser types which are:
Tapping (any number of taps) - UITapGestureRecognizer
Pinching in and out (for zooming a view) - UIPinchGestureRecognizer
Panning or dragging - UIPanGestureRecognizer
Swiping (in any direction) - UISwipeGestureRecognizer
Rotating (fingers moving in opposite directions) -
UIRotationGestureRecognizer
Long press (also known as “touch and hold”) -
UILongPressGestureRecognizer
If this isn't what you need you can create a subclass of UIGestureRecognize and come up with your own solution. You can find everything you need on this topic in Apple Docs.
Since iOS 9 there's a "Peek an Pop" action aka hard press aka 3D touch - some might consider this a gesture too, but it's a little bit more complicated. You can find some info here.

May I know what exactly requireGestureRecognizerToFail will do?

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.

UIGestureRecognizer Method Clarification

Hi any one can explain me, what are the cases can i use the following UIGestureRecognizer Methods.
1. - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer*)preventingGestureRecognizer
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
2. - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer
3. - (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
Kindly give the use case of all this three methods, if u have any example kindly comment here.
Thanks in advance.
Please read the Apple's Documentation.
canBePreventedByGestureRecognizer:
Overridden to indicate that the specified gesture recognizer can prevent the receiver from recognizing a gesture.
canPreventGestureRecognizer:
Overridden to indicate that the receiver can prevent the specified gesture recognizer from recognizing its gesture.
requireGestureRecognizerToFail:
Creates a dependency relationship between the receiver and another gesture recognizer.
shouldBeRequiredToFailByGestureRecognizer:
Overridden to indicate that the receiver should be required to fail by the specified gesture recognizer.
shouldRequireFailureOfGestureRecognizer:
Overridden to indicate that the receiver requires the specified gesture recognizer to fail.
All those methods simply establish dependancies of different types between different recognizers. Certain gesture recognizers may use similar gestures, and these are typically set up so that one takes precedence over another.
For example, a scrolling gesture and a swipe gesture are similar in that they both involve a touch moving in a particular direction, so you might set up the swipe recognizer such that it requires the scrolling recognizer to fail before the swipe can be recognized. Or, you could set them up so that the scrolling recognizer prevents the swipe recognizer from being activated while the user is scrolling.

How to differentiate between user swipe and tap action?

I am developing a app in which I have a view which contains subView in it.
I want to track both swipe and tap actions such as a single click.
Actions should be tracked only when the user touches within my subview. When the user taps I want to perform one action, when the user swipes I want perform another.
For tracking the swipe, I implemented UIGestureRecognizer and it is working fine. But I don't know how to track the tap option. Please guide me how to achieve this.
The main thing is, when I tap it should call tap action only and vice versa.
You can use UITapGestureRecognizer for tap gestures.
"UITapGestureRecognizer is a concrete subclass of UIGestureRecognizer
that looks for single or multiple taps. For the gesture to be
recognized, the specified number of fingers must tap the view a
specified number of times."
This method includes the numberOfTapsRequired ("The number of taps for the gesture to be recognized.") and numberOfTouchesRequired ("The number of fingers required to tap for the gesture to be recognized") properties where you can set exactly how you want it to react to user action.
In this case, as you only want it to be activated when tapped once, the default settings for both these properties (both have default values of 1) should be fine.
The best place to get the information is Defining How Gesture Recognizers Interact of Event Handling Guide for iOS
When a view has multiple gesture recognizers attached to it, you may
want to alter how the competing gesture recognizers receive and
analyze touch events. By default, there is no set order for which
gesture recognizers receive a touch first, and for this reason touches
can be passed to gesture recognizers in a different order each time.
You can override this default behavior to:
Specify that one gesture recognizer should analyze a touch before another gesture recognizer.
Allow two gesture recognizers to operate simultaneously.
Prevent a gesture recognizer from analyzing a touch.

Resources