I am overriding my horizontal image UIScrollView with a panning gesture recognizer to detect a user swipe.
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureCaptured)];
[imgHorizontalScrollView addGestureRecognizer:panGesture];
My question is: Is there a way for me to reset imgHorizontalScrollView's pan gesture recognizer back to default in the panGestureCaptured method? The reason I ask is because since I am overriding this gesture, once the user swipes and the gesture is picked up, I am no longer able to scroll in the scroll view. I also tried to remove the gesture but that also prevents me from being able to scroll.
try UIGestureRecognizerDelegate gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: with scrollView's gestureRecognizer got by panGestureRecognizer
Try setting
panGesture.cancelsTouchesInView = NO;
If that doesn't work, you should find a way to change your gesture handler to the scrollViewDidScroll: delegate method
Related
I am currently facing a scenario that I am using a UIPageViewController on a view & I want the right swipe gesture to work when user swipe right side from index value 0, so I am trying to add a right swipe gesture to UIPageViewController by the following code:
UISwipeGestureRecognizer *rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
rightRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[rightRecognizer setNumberOfTouchesRequired:1];
//Edit 1
[self.pageViewController.view addGestureRecognizer:rightRecognizer];
but, while I am adding gesture to pageviewcontroller I am getting following error message (Solved by #Lyndsey Scott answer)
no visible interface uipageviewcontroller declares the selector addgesturerecognizer
Can anyone guide me that how can I implement the right swipe in this pageViewController
Edit 1: Replaced the code provided by #Lyndsey Scott, removed the error, but problem still exists that I am not able to trigger that swipe event.
You have to the gesture to the UIPageViewController's view:
[self.pageViewController.view addGestureRecognizer:rightRecognizer];
Edit in response to your edit:
The swipe gesture won't work if you haven't implemented any UIGestureRecognizerDelegate methods to allow for the UIPageViewController's swipe gesture and your swipe gesture to be recognized simultaneously. Right now, your swipe is essentially being blocked by the page controller's gesture. You could change that by implementing the UIGestureRecognizerDelegate, setting rightRecognizer.delegate = self;, and overriding gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer such that it returns true in the case that both gesture recognizers are triggered.
But if you want the page to flip and your gesture to be recognized at the time of that page flip, adding the extra swipe gesture is unnecessary since you can simply trigger your method upon page turn; for example in pageViewController:didFinishAnimating:previousViewControllers: transitionCompleted:.
You shouldn't have to add the gesture recognizer, if you implement the protocol correctly it should work out of the box.
The point of UIPageViewController is to not have to do it manually.
I have two UIButtons in a view (one is YES, the other NO). I now want to add a "did not answer", which would be indicated by a downward swipe on the view.
The problem is that the user may swipe down on the view, but in the process hit one of the buttons. When this happens I want to ignore the button press if there was a swipe underway. If it is just a tap on a button, the answer is recorded.
So, if the swipe occurs, I want to call the swipe gesture's action method. If it is determined no swipe occurred but one of the two buttons was touched I want to call their respective action methods. But if a button was touched in the process of a swipe, I want to call only the swipe gesture's action method.
I know there is a way but I'm wondering whether there is an EASY way of doing this. TIA for suggestions.
Since UISwipeGestureRecognizer is a "discrete" gesture, it just triggers a single action when recognized and it won't allow you to detect the end of the gesture.
So to prevent other touches during the gesture, I'd recommend using a UIPanGestureRecognizer instead since it can track your gesture from beginning to end. Then you can try setting your gesture's cancelsTouchesInView property to YES to cancel all other touches in the view that happen while that pan gesture is recognized, ex:
gesture.cancelsTouchesInView = YES;
gesture.delaysTouchesBegan = YES;
Your buttons should be registering touch up in view, so that someone who taps on the button can drag off if they decide not to proceed.
For your other swipe gesture, your buttons will not register a touch up in view during a swipe gesture, even if the swipe passes over the button or ends on it.
Okay, this seems to work. On the gesture recognizer, I used:
UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipeDown:)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
swipeDown.delaysTouchesBegan = YES;
swipeDown.delegate = self;
[self addGestureRecognizer:swipeDown];
They delaysTouchesBegan = YES allows it to determine whether the swipe has occurred before passing the touches on to the buttons. So, if you swipe, it calls the swipe GR, and if you touch either button, you get that. Thanks for your answers...
I want to have UITapGestureRecognizer in a view and touchesBegan in its childview, but the problem is when UITapGestureRecognizer is recognized touchesBegan is not called.
Is it doing this is fine? Or should I need to take another approach ?
Edit : Solved. Setting cancelsTouchesInView property of UITapGestureRecognizerdid the trick for me. By default it is false, so touchesBegan isn't called.
Please find out where are you wrong,
This is a step by step guide on how to implement gesture recognizers in your class:
Conform your class to UIGestureRecognizerDelegate protocol.
Instantiate the gesture recognizer. For example, to instantiate a UITapGestureRecognizer, we will do:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapFrom:)];
Here, action is the selector which will handle the gesture. Here, our selector handleTapFrom will look something like:
- (void) handleTapFrom: (UITapGestureRecognizer *)recognizer
{
//Code to handle the gesture
}
The argument to the selector is the gesture recognizer. We can use this gesture recognizer to access its properties, for example, we can find the state of the gesture recognizer, like, UIGestureRecognizerStateBegan, UIGestureRecognizerStateEnded, etc.
Set the desired properties on the instantiated gesture recognizer. For example, for a UITapGestureRecognizer, we can set the properties numberOfTapsRequired, and numberOfTouchesRequired.
Add the gesture recognizer to the view you want to detect gestures for. In our sample code (I will be sharing that code for your reference), we will add gesture recognizers to an imageView with the following line of code:
[self.imageView addGestureRecognizer:tapGestureRecognizer];
After adding the gesture recognizer to the view, set the delegate for the gesture recognizer, i.e. the class which will handle all the gesture recognizer stuff. In our sample code, it would be like:
tapGestureRecognizer.delegate = self;
Note: Assign the delegate after adding the gesture recognizer to the view. Otherwise, the action method won’t be called.
I add a swipeUp gesture to the whole view.
I add a longPressGestureRecognizer to the whole view, set its minimunPressDuration equals 0.001f so that it can both detect press down action and touches move action, then call the requireGestureToFail function:
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressed:)];
longPressGestureRecognizer.minimumPressDuration = 0.001f;
[longPressGestureRecognizer requireGestureRecognizerToFail:swipeGestureRecognizer];
The problem is:
When user press and hold (don't move) a button, the longPress gesture's state remains UIGestureStatePossible because the swipeUp gesture doesn't fail, So that it won't react to user touch.
If I don't call requireGestureRecognizerToFail all the gesture including swipeUp gesture will be recognised as longPress gesture.
Implmenting shouldRecognizeSimultaneouslyWithGestureRecognizer: is not what I expect.
What I want is when press and hold(don't move) a button, it triggers longPress, then if user swipe up it triggers swipeUp gesture, if user drags but the touch pattern doesn't fit swipeUp it still triggers longPress.
How can I implement this?
I think it would be easier to implement your own UIGestureRecognizer or UIView subclass with multiple gestures. Check this out:
UITapGestureRecognizer - make it work on touch down, not touch up?
https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/GestureRecognizer_basics/GestureRecognizer_basics.html#//apple_ref/doc/uid/TP40009541-CH2-SW2
I have a view controller that consists of three views (self.panedview, self.view, self.sineview) When a swipe up gesture is detected, the highest view (self.panedview) is moved up halfway - revealing two additional views (self.view and self.sineview). self.sineview is a UIView that constantly has an animation running that renders a moving sinewave and takes up half of self.view. I have a swipe down gesture recognizer that works when I swipe down on self.panedview, but doesn't work when I swipe down on self.sineview. If I swipe around self.sineview on self.view it seems to work. When I hide self.sineview and swipe directly down on either self.view or self.paned view, the swipe down works. do you think the animating sine wave gets in the way of the gesture recognition.
UISwipeGestureRecognizer * swipeDownRec = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleDownSwipe:)];
[self.panedView addGestureRecognizer:swipeDownRec];
[self.view addGestureRecognizer:swipeDownRec];
[self.sineview addGestureRecognizer:swipeDownRec];
Also I tried varying between these two lines of code but there is no difference:
[self.view insertSubview:self.sineWave belowSubview:self.panedView];
[self.view insertSubview:self.sineWave aboveSubview:self.view];
I also tried adding a separate swipe down gesture recognizer for each view, but it still doesn't work.
The problem was the that the swipe recognizer for self.sinewave couldn't be recognized while the self.sinewave animation was enabled. The solution is simple: add UIViewAnimationOptionAllowUserInteraction as a parameter to the options handler for animateWithDuration:delay:options:animations:completion: