I'm writing a module that everytime I swipe on a view, two sub views with a half size of the view will be added. Those subviews have their own gestures (eg: pan,...). The first time I swipe, it's OK because none of subview has been created. But once the subview been created, everytime I swipe, the swipe gesture is alway pass to its subviews. :(, so I have to swipe 2 times to divide.
I want to know is there any way to block swipe passing to its subview? Thank you.
UPDATE
I used shouldRecognizeSimultaneouslyWithGestureRecognizer to make those gestures work simultaneously. But there's still have some problems. The parent view have its Swipe gesture, the subview have its Pan gesture. Since I use souldRecognizeSimultaneouslyWithGestureRecognizer, sometime when I'm panning, the swipe gesture triggers. So, you know how to disable Swipe while Pan is active in this situation?
You have to implement the UIGestureRecognizerDelegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
And add your controller as the delegate of the gesture recognizers. Then, when two gesture recognizers respond to a gesture, this method will be called and here you can implement the logic you want for your app.
In the interface declaration of the controller you have to type:
@interface testcViewController () <UIGestureRecognizerDelegate>
Then, when creating the gesture recognizer:
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipe.direction = UISwipeGestureRecognizerDirectionDown;
swipe.delegate = self;
[self.view addGestureRecognizer:swipe];
And then, finally, you add this method to the controller:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
BOOL shouldInteract = NO;
//Here you decide whether or not the two recognizers whould interact.
return shouldInteract;
}
EDIT
You can also implement
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
And here, detect if you have already presented the subviews, and block any gesture you want.
set userinteractionEnabled to NO of your subView
subview.userinteractionEnabled=NO
if you dont want to disable userInteraction then use cancelsTouchesInView
method
cancelsTouchesInView—If a gesture recognizer recognizes its gesture,
it unbinds the remaining touches of that gesture from their view (so
the window won’t deliver them). The window cancels the previously
delivered touches with a (touchesCancelled:withEvent:) message. If a
gesture recognizer doesn’t recognize its gesture, the view receives
all touches in the multi-touch sequence.
To block all gesture recognizers from superviews I created a UIGestureRecognizer sub class that will do just that when attached to a view. See the following code (taken from my WEPopover project):
#import "WEBlockingGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@implementation WEBlockingGestureRecognizer
- (id)init {
return [self initWithTarget:self action:@selector(__dummyAction)];
}
- (id)initWithTarget:(id)target action:(SEL)action {
if ((self = [super initWithTarget:target action:action])) {
self.cancelsTouchesInView = NO;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateRecognized;
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer {
return [self isGestureRecognizerAllowed:preventingGestureRecognizer];
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer {
return ![self isGestureRecognizerAllowed:preventedGestureRecognizer];
}
- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return ![self isGestureRecognizerAllowed:otherGestureRecognizer];
}
- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return NO;
}
- (BOOL)isGestureRecognizerAllowed:(UIGestureRecognizer *)gr {
return [gr.view isDescendantOfView:self.view];
}
- (void)__dummyAction {
}
@end
If you want to block all gesture recognizers attached to parent views of some view, just do the following:
- (void)blockParentGesturesForView:(UIView *)v {
[v addGestureRecognizer:[WEBlockingGestureRecognizer new]];
}
try like this,
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return NO;
}
Considering that I have a dialogView
as a direct subview of my UIViewController
's main view
I'm attaching a gesture recognizer to the main view
and do the following (setting my view controller as the gesture recognizer delegate)
:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
let point = touch.location(in: view)
return !dialogView.frame.contains(point)
}