Receiving gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer when gestureRecognizerShouldBegin: returned NO - ios

I have a view that has a UIPanGestureRecognizer. That same view also contains a UIScrollView.
When the user pans over the ScrollView, I return NO in gestureRecognizerShouldBegin:, to make sure that the ScrollView's gesture recognizer takes over the gesture.
However, I still receive the gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: message. It is easy to fix, I simply need to return NO in gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:, but I was wondering if it is normal to receive this message after returning NO to gestureRecognizerShouldBegin:.
Code
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
NSLog(#"gestureRecognizerShouldBegin:0x%x - return NO", (int)gestureRecognizer);
return NO;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
NSLog(#"gestureRecognizer:0x%x shouldRecognizeSimultaneouslyWithGestureRecognizer:0x%x", (int)gestureRecognizer, (int)otherGestureRecognizer);
return YES;
}
Output
2013-03-04 11:30:14.876 XXXX[99271:19d03] gestureRecognizerShouldBegin:0x9d6c380 - return NO
2013-03-04 11:30:14.876 XXXX[99271:19d03] gestureRecognizer:0x9d6c380 shouldRecognizeSimultaneouslyWithGestureRecognizer:0xbb75240

I think this behaviour is ok.
From the following reference of gestureRecognizerShouldBegin: method from official doc Discussion:
This method is called when a gesture recognizer attempts to transition out of the UIGestureRecognizerStatePossible state. Returning NO causes the gesture recognizer to transition to the UIGestureRecognizerStateFailed state.
This clearly indicates that it will not prevent the gesture recognizer but it will make the transition to UIGestureRecognizerStateFailed state of respective gesture recognizer. So other delegate methods will be called as normal.

Related

ios swipe after longpress is ended, without lifting the finger

I want to implement back navigation, using longpress and swipe to the left, without lifting the finger, but the swipe gesture isn't recognised, if I don't lift the finger after the longpress.
I also implemented the following delegate method, but the desired result isn't appearing. Any thoughts?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer == _longPress && otherGestureRecognizer == _swipe) {
return YES;
}
if (gestureRecognizer == _swipe && otherGestureRecognizer == _longPress) {
return YES;
}
return NO;
edit:
- the longpress gesture fires method, which changes the background color of the current UIViewController (made it, just to see, if it fires).
-the swipe gesture fires method, -popViewController:animated
Don't use 2 different gesture recognisers because this is 1 gesture. You should create a custom gesture subclass to encode your logic so it's a single logical gesture for you to add and for the user to execute.
Inside your gesture i'd have a small state machine so you know when you start, when the long press time is up, if they have actually swiped enough. From each state you're only looking for one thing to happen, if anything else happens then you know it's a failure and the gesture can fail out.

Adding a UIGestureRecognizer taking priority over all other interactions

When I tap on a UIButton, a UIView MyView appear from the bottom a cover a third of the screen. I would like that when I tap somewhere outside this view, it disappears.
I thought about adding another transparent UIView right under MyView and add a tab gesture on it with the dismiss function but I'm sure there is something cleaner than this.
So I thought about adding the tap gesture MyTapGesture to dismiss MyView on self.view of the UIViewController. The problem is that outside this view, I have other UIControls and gestures that capture also any touch at the same time than MyTapGesture.
How can I make MyTapGesture the priority gesture outside MyView and ignore all other gesture, taps, etc...?
You may have to use the gesture delegate methods to handle two tapGestureRecognizer activate the one you need depending on scenario
#pragma mark - UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([tapGestureRecognizer1 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer2 isEqual:otherGestureRecognizer];
}
if ([tapGestureRecognizer2 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer1 isEqual:otherGestureRecognizer];
}
return NO;
}

How to avoid to trigger a UIPanGestureRecognizer when there is a tap on a UIButton?

I have added UIPanGestureRecognizer on the view of my UIViewController.
In this view (a calculator) are some UIButton triggered by the event .TouchUpInside.
The problem comes if I tap on the button and make a small pan at the same time (which might happen if you tap quickly a button and are moving to the next one at the same time). Then the pan gesture is triggered. I would like to avoid it when there is a tap on a button. But I would like to allow it if the tap takes too long (let say 0.3s is enough to trigger the pan gesture).
How can I achieve that?
Set the property cancelsTouchesInView of your gesture recognizer to NO.
Then your button should work properly.
You can use the delegate method like this-
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
There is a dirty solution. You can just grab it in a UIScrollView

Getting all touch events of an app

I've been looking for a way to intercept all touch events of an app.
I saw that I can add a gesture recognizer to the main window and get all the touches by using it's delegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
NSLog(#"%#",touch);
return NO;
}
This way I don't harm all of the other touch events the app has.
The problem is that I cannot get swipe events and such this way. Moreover, I cannot override UIWindow sendEvents because my app is an outside framework.
I also do not want to add a transparent UIView on top.
Is there any other way to get swipes and other gesturs?
To intercept all touch events of an app, use a UIWindow subclass and override sendEvent:.... Every touch event passes through this bottleneck method. Be warned that you are now operating at a very low level and can easily break everything.
I managed to get this to work by using a custom gesture recognizer attached to the keyWindow and with using the method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
Which also gives me all the touches and doesn't disturb any other recognizers.
If anyone know why I shouldn't be doing that, I'd be happy to hear about it.

How to unblock pan and pinch events in a UIScrollViewDelegate?

I have a UIView which has a UIScrollView subview and is a UIScrollViewDelegate. Since I've implemented viewForZoomingInScrollView I stopped getting pan and pinch events for the UIView.
How can I get these events back?
Try adding a delegate to your gesture recognizer that implements
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
try:
[yourviewname setUserInteractionEnabled:YES];
Edit: I just re-read your question. Are you saying that you can't pan and/or pinch? Or are you saying that you aren't being notified when you pan and/or pinch?

Resources