user523234
user523234

Reputation: 14834

UITapGestureRecognizer does not respond to subview area outside parent view

I have a UIView called view1. view1 has a subview called subview. I added UITapGestureRecognizer to subview as follow:

UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];
[subview addGestureRecognizer:recognizer];

If I tapped an area overlapped between subview and view1 then the handleTap method got called. But if I tapped an area on the subview that was outside view1, then handleTap never got called. Is this behavior right? If not, any suggestion to what should I check for?

btw: The UIPanGestureRecognizer works fine. It does not exhibit the behavior mentioned above.

enter image description here

Upvotes: 7

Views: 3645

Answers (4)

claude31
claude31

Reputation: 884

Probably the simplest way is to move subview at the top level of hierarchy, set constraints so that it is positioned correctly and put subview below view1 in storyboard list of objects (so that subview sits over view1). Of course, we loose some advantages of putting inside view1 (as automatic hiding when view1 is hidden…

Upvotes: 0

Andrea
Andrea

Reputation: 26385

That is the default behaviour of UIView, the subview should be inside parent view bounds. If you want something different is better you create a custom subclass of the top view and override (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

Upvotes: 2

David
David

Reputation: 105

I've found the answers talking about overriding pointInside:withEvent: to be lacking detail on explanation or implementation. In the original question, when the user taps in the black, unlabeled area/view (we'll call it view2), the event framework will only trigger hitTest:withEvent: for the main window down through the view2 (and its immediate subviews), and will never hit it for view1 because the point tested for in pointInside:point is outside of the bounds of view1's frame. In order to get subview1 to register the gesture, you should override view2's implementation of hitTest:withEvent to include a check for subview's pointInside:point

//This presumes view2 has a reference to view1 (since they're nested in the example).
//In scenarios where you don't have access, you'd need to implement this
//in a higher level in the view hierachy

//In view2
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        let ptRelativeToSubviewBounds = convert(point, to: view1.subview)
        if view1.subview.point(inside:ptRelativeToSubviewBounds, with:event){
            return view1.subview
        }
        else{
            return super.hitTest(point, with: event)
        }

Upvotes: 1

Jiri
Jiri

Reputation: 2206

You need to customize the parent view and change the way it handles touches. See this question for more details.

Upvotes: 1

Related Questions