Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exclude subviews from UIGestureRecognizer

I have a UIView (the 'container view') which contains several 'sub views'. I want to add a UITapGestureRecognizer to the container view, such that it is activated when I touch the region inside the container view but outside the subviews.

At the moment, touching anywhere inside the container view, including inside the subviews activates the gesture recognizer.

The implementation looks something like this: In the controller:

ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array];
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)];
[containerView addGestureRecognizer:tap];
[self.view addSubView:containerView];

In ContainerView.m

-(id)initWithSubviews:(NSArray *)array {
    for (subView *s in array) {
        [self addSubView:s];
    }
    return self;
}

I think the problem occurs because the gesture recognizer is added after the subviews are. If that is true then the solution would require breaking the initWithSubViews method into two separate ones, which I would prefer to avoid.

Thank You

like image 716
Awais Hussain Avatar asked Mar 17 '13 03:03

Awais Hussain


3 Answers

I used the simple way below. It works perpectly!

Implement UIGestureRecognizerDelegate function, accept only touchs on superview, not accept touchs on subviews:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews
        return NO;
    }

    return YES;
}
like image 70
vietstone Avatar answered Nov 01 '22 14:11

vietstone


iOS 6 introduces a great new feature that solves this exact problem - a UIView (subview) can return NO from gestureRecognizerShouldBegin: (gesture recognizer attached to a superview). Indeed, that is the default for some UIView subclasses with regard to some gesture recognizers already (e.g. a UIButton with regard to a UITapGestureRecognizer attached to a superview).

See my book on this topic: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

like image 32
matt Avatar answered Nov 01 '22 14:11

matt


I managed to get it working by doing the following:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];

// ...

-(void) tapGestureHandler:(UITapGestureRecognizer *)sender {
    CGPoint point = [sender locationInView:sender.view];
    UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
    if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) {
        // Do nothing;
    } else {
        // respond to touch action
    }
}
like image 13
Awais Hussain Avatar answered Nov 01 '22 15:11

Awais Hussain