Question

I recently came across an issue where I had a superview that needed to be swipable and a subview that also needed to be swipable. The interaction was that the subview should be the only one swiped if the swipe occurred within its bounds. If the swipe happened outside of the subview, the superview should handle the swipe.

I couldn't find any answers that solved this exact problem and eventually came up with a hacky solution that I thought I'd post if it can help others.

Edit: A better solution is now marked as the right answer.

Changed title from "Ignore touch events..." to "Ignore gestures..."

Was it helpful?

Solution

If you are looking for a better solution, you can use gestureRecognizer:shouldReceiveTouch: delegate method to ignore the touch for the parent view recognizer.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch{
  UIView* swipeableSubview = ...; //set to the subview that can be swiped
  CGPoint locationInSubview = [touch locationInView:swipeableSubview];
  BOOL touchIsInSubview = [swipeableSubview pointInside:locationInSubview withEvent:nil];
  return !touchIsInSubview;
}

This will make sure the parent only receives the swipe if the swipe does not start on the swipeable subview.

OTHER TIPS

The basic premise is to catch when a touch happens and remove gestures if the touch happened within a set of views. It then re-adds the gestures after the gesture recognizer handles the gestures.

@interface TouchIgnorer : UIView
@property (nonatomic) NSMutableSet * ignoreOnViews;
@property (nonatomic) NSMutableSet * gesturesToIgnore;
@end
@implementation TouchIgnorer
- (id) init
{
    self = [super init];
    if (self)
    {
        _ignoreOnViews = [[NSMutableSet alloc] init];
        _gesturesToIgnore = [[NSMutableSet alloc] init];
    }
    return self;
}
- (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    CGPoint relativePt;
    for (UIView * view in _ignoreOnViews)
    {
        relativePt = [view convertPoint:point toView:view];
        if (!view.isHidden && CGRectContainsPoint(view.frame, relativePt))
        {
            for (UIGestureRecognizer * gesture in _gesturesToIgnore)
            {
                [self removeGestureRecognizer:gesture];
            }
            [self performSelector:@selector(rebindGestures) withObject:self afterDelay:0];
            break;
        }
    }
    return [super pointInside:point withEvent:event];
}

- (void) rebindGestures
{
    for (UIGestureRecognizer * gesture in _gesturesToIgnore)
    {
        [self addGestureRecognizer:gesture];
    }
}
@end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top