Detect touch screen in iOS - ios

Now I have implemented the fling feature in my ios app, but I want to stop the fling when a touch on screen happens, this does not only contain tap gesture, maybe other like long press or pinch, I have a BOOL value to indicate whether a touch happens, so should I add all kinds of gesture recognizers and set to BOOL value as true? Are there any simple solution? Thank you!

There are several methods in UIGestureRecognizerDelegate that will achieve what you want. gestureRecognizerShouldRegognizeSimultaneouslyWithGesture sounds like the best candidate. You will get passed two gesture recognizers. One will be your swipe gesture (the one you want to keep), the other will be the one you want to cancel (tap, long press, pinch) return NO in the correct scenario.
See docs: https://developer.apple.com/documentation/uikit/uigesturerecognizerdelegate

Related

Proper UIGestureRecognizer and Delegate design

This is a pretty hypothetical question just to understand proper design but lets say I have two custom UIViews.
One of them is essentially a container that I'll call a drawer. Its purpose is to hide and show content. It's a lot like the notification center on iOS where you swipe to pull it open and flick it back up to close it. It's a generic container than can contain any other UIView. It has a UIPanGestureRecognizer to track the finger that's pulling it open/closed. It might also have a UISwipeGestureRecognizer to detect a "flick".
The other view is a custom map widget that has UIPan/Rotation/Pinch GestureRecognizers.
I think the drawer view should be the UIGestureRecognizerDelegate for the Pan/Swipe GestureRecognizers so that it can prevent touches from being delivered unless the user is grabbing "the handle".
My first instinct is for the map to be the UIGestureRecognizerDelegate of the pan/rotation/pinch gestures so that it can allow them to all run simultaneously.
The problem I'm having is that, I really don't want the map to receive any touches or begin recognizing gestures until the drawer is completely open. I'd like to be able to enforce this behavior automatically in the drawer itself so that it works for all subviews right out of the box.
The only way that I can think to do this is to wire all of the gestures handlers to the ViewController and let it do everything, but to me that breaks encapsulation as now it has to know that the map gestures need to run simultaneously, that the drawer should only get touches on it's handle and that the map should only get touches when it's open.
What are some ways of doing this where the logic can stay in the Views where I think it belongs?
I would do something like this to make the subviews of the drawer disabled while panning. Essentially loop through the drawer's subviews and disbale interaction on them.
[self.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop){
subview.userInteractionEnabled = NO;
}];
And something similar again for when you want to re-enable user interaction on the subviews.
This should already Just Work™. A gesture recogniser is attached to a view; when a continuous gesture is recognised, all subsequent touches associated with that gesture are associated with that view.
So in your case, when the drawer pan is recognised, no touches associated with that pan should ever cause behaviour in your map view's pan/pinch/rotation gestures (unless you explicitly specify that they should using the appropriate delegate methods).
Or do you mean that you want to prevent the user from, halfway through opening the drawer, using another finger (i.e. another gesture) to start scrolling the (half-visible) map? If so, you should just set userInteractionEnabled on the drawer's contentView (or equivalent) to NO at UIGestureRecognizerStateBegan/Changed and YES again at UIGestureRecognizerStateEnded/Cancelled.

Accurate start position for UIPanGestureRecognizer?

I am using a UIPanGestureRecogniser to implement drag and drop. When the drag starts I need to identify the object that is being dragged. However the objects are relatively small. And if the user doesn't hit the object right in the centre of the object it isn't getting dragged.
The problem is that when the gesture handler is first called with the state UIGestureRecognizerStateBegan, the finger has already moved several pixels, and so [UIPanGestureRecognizer locationInView:] returns that point, which is not where the gesture truly started. That makes sense as it can only recognize a pan after a few pixels of movement. However, I need the absolute start of the gesture, not the position after the gesture has first been recognized.
I'm thinking that maybe I need to implement a tap gesture recognizer as well, purely to capture the first touch. But that seems like a hack for what is not an unusual requirement. Is there no other way of getting that first touch from within the pan gesture recognizer?
UIGestureRecognizerDelegate protocol provides methods gestureRecognizerShouldBegin: and gestureRecognizer:shouldReceiveTouch: that can help you evaluate the touches before the pan has transitioned to state UIPanGestureRecognizerStateBegan

ios UIGestureRecognizer for longpress, then swipe

I'm using a UIGestureRecognizer to recognize a single tap, a double tap and a longpress.
What I would like to do is also recognize a longpress, then swipe to either left or right.
Would this be possible given that I'm already consuming a longpress? I'm confused on this one and would appreciate pointers on how to do.
Thanks
Just tried this out myself and it seems as if the UILongPressGestureRecognizer will transition to its end state as soon as the UISwipeGestureRecognizer begins. Just make sure shouldRecognizeSimultaneouslyWithGestureRecognizer: returns YES for this gesture combination.
You'd need to use two gesture recognisers and make sure you track the state of the long press one when you receive a callback to say it's ended, and then do something based on the swipe/pan gesture following it.

iOS: Two Gestures, One Target-Action

I'm implementing the Messages app copy-message feature.
You can either double tap or long press on a message to copy it.
How do I do that?
I was thinking of adding two gesture recognizers to the view, one UITapGestureRecognizer (with numberOfTapsRequired set to 2) and one UILongPressGestureRecognizer. They would both have the same target & action.
Then, I think for each of them, I'd call requireGestureRecognizerToFail:, passing the other gesture recognizer.
Is my thinking correct? Is there anything I'm missing, or is there a better way to do this?
Simply add the gestures to your view (easy to do programatically) and set the selector to the desired method. However, you're probably going to get some push back since you don't provide any code or hint that you have tried to solve your problem before coming here. I'm new here as well, but have seen some questions put on hold for those reasons.
As you said that for double tap and long press on a message to copy. So both of them are using for same action. So I think you can do it on same method.
You can try this method in UIGestureRecognizerDelegate
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
refer this for more detail:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIGestureRecognizerDelegate/gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
this helps recognize more than one gesture recognizer at a time.
Yes, as you say, create two gesture recognizers (one long-press and one double-tap) and add them both to the same view.
Don't call requireGestureRecognizerToFail: on either of them because long-press & double-tap gestures play nice together by default.
You can give them both the same target and action, but each gesture requires different logic to determine whether you should show the copy menu.
- (void)messageCopyMenuShowAction:(UILongPressGestureRecognizer *)gestureRecognizer
{
BOOL doubleTap = (gestureRecognizer.numberOfTapsRequired == 2);
if ((doubleTap && gestureRecognizer.state == UIGestureRecognizerStateEnded) || // double-tap
(!doubleTap && gestureRecognizer.state == UIGestureRecognizerStateBegan)) { // long-press
// Show copy menu.
}
}

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