Setup: I have parent view A. It has a child view B. B is partially inside the bounds of A, but partially outside (A has clipsToBounds=false). I have attached UITapGestureRecognizer (UITGR) to B.
Observed: UITGR fires OK when I tap on the portion of B that is within the bounds of A. UITGR does NOT fire when I tap on the portion of B that is outside the bounds of A.
Expected/question: How do I make UITGR fire when I tap on the portion of B that is outside the bounds of A?
This quote will answer your question as to why it behaves like that:
Touch events. The window object uses hit-testing and the responder chain to find the view to receive the touch event. In hit-testing, a window calls hitTest:withEvent: on the top-most view of the view hierarchy; this method proceeds by recursively calling pointInside:withEvent: on each view in the view hierarchy that returns YES, proceeding down the hierarchy until it finds the subview within whose bounds the touch took place. That view becomes the hit-test view. (source)
One workaround is to create your own UITapInSubviewsView
with the following definition for hitTest
:
(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSEnumerator *reverseE = [self.subviews reverseObjectEnumerator];
UIView *iSubView;
while ((iSubView = [reverseE nextObject])) {
UIView *viewWasHit = [iSubView hitTest:[self convertPoint:point toView:iSubView] withEvent:event];
if(viewWasHit)
return viewWasHit;
}
return [super hitTest:point withEvent:event];
}
Then you use this class for your parent view.
(I found this code in a post from S.O. a few weeks ago, but I cannot seem to find it anymore; so just copied it from my project).
Update of @sergio's answer for Swift 4.2:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let reversedSubviews = subviews.reversed()
let hitSubview = reversedSubviews
.first(where: { $0.hitTest(convert(point, to: $0), with: event) != nil })
if hitSubview != nil {
return hitSubview
}
return super.hitTest(point, with: event)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With