Passing through touches to UIViews underneath
I have a another solution. I have two views, let's call them CustomSubView
that were overlapping and they should both receive the touches. So I have a view controller and a custom UIView class, lets call it ViewControllerView
that I set in interface builder, then I added the two views that should receive the touches to that view.
So I intercepted the touches in ViewControllerView
by overwriting hitTest:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
Then I overwrote in ViewControllerView
:
- (void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
for (UIView *subview in [self.subviews reverseObjectEnumerator])
{
if ([subview isKindOfClass:[CustomSubView class]])
{
[subview touchesBegan:touches withEvent:event];
}
}
}
Do the exact same with touchesMoved
touchesEnded
and touchesCancelled
.
Select your View
in Storyboard
or XIB
and...
Or in Swift
view.isUserInteractionEnabled = false
The UIGestureRecognizer is a red herring I think. In the end to solve this I overrode the pointInside:withEvent:
method of my UIView:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL pointInside = NO;
if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;
return pointInside;
}
This causes the view to trap all touches if you touch either the imageView or if its expanded flag is set. If it is not expanded then only trap the touches if they are on the imageView.
By returning NO, the top level VC's View queries the rest of its view hierarchy looking for a hit.
Look into the UIGestureRecognizerDelegate Protocol. Specifically, gestureRecognizer:shouldReceiveTouch:
You'll want to make each UIGestureRecognizer
a property of your UIViewController
,
// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;
// .m
@synthesize lowerTap;
// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer
Make sure you make your UIViewController
a delegate,
[self.lowerTap setDelegate: self];
Then, you'd have something like this,
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (expanded && gestureRecognizer == self.lowerTap) {
return NO;
}
else {
return YES;
}
}
Of course, this isn't exact code. But this is the general pattern you'd want to follow.