Max
Max

Reputation: 5932

UITapGestureRecognizer only detects parent view tap

I am using UITapGestureRecognizer for detecting which UIView was tapped on my screen but for some reason it only detects the parent view tap, for example below code logs only parent views tag. How do i detect subview taps which are present on main view. Please suggest.

Inside View did load :- 

UITapGestureRecognizer *viewTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(actionForViewTapped:)];
    [self.view addGestureRecognizer:viewTapRecognizer];

Method outside view did load.

-(void) actionForViewTapped:(UITapGestureRecognizer*)sender {
    NSLog(@"view tapped");
    UIView *view = sender.view;
    NSLog(@"view tag is %lu", view.tag); //Always prints parent view tag. 

    if(view.tag == 10){
        NSLog(@"tag1 tapped"); //Not called
    }
    if(view.tag == 20){
        NSLog(@"tag 2 tapped"); //Not called
    }
}

Upvotes: 3

Views: 4247

Answers (2)

user3182143
user3182143

Reputation: 9589

We have more options to find detecting on sub view by tap gesture

CHOICE 1:Directly tap to SubView

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapSubView)];
tapGesture.numberOfTapsRequired = 1;
[subView addGestureRecognizer:tapGesture];

CHOICE 2:Finding tap on SubView through Parent View

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapSubView)];
tapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGesture];


-(void)tapSubView:(UITapGestureRecognizer *)sender
{
   UIView* view = sender.view;
   CGPoint loc = [sender locationInView:view];
   UIView* subview = [view hitTest:loc withEvent:nil];
               //OR
   CGPoint point = [sender locationInView:sender.view];
   UIView *viewTouched = [sender.view hitTest:point withEvent:nil];

   if ([viewTouched isKindOfClass:[self.view class]])
   {
      NSLog(@"the subView is called");
   } 
   else 
   {
      NSLog(@"the subView is not called");
   }
}

Printed Output is

the subView is called

CHOICE 3:Find Tap Detection using Delegate methods of Gesture

First You have to add the GestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{
  if([touch.view isKindOfClass: [self.view class]] == YES)
  {
    return YES; // return YES (the default) to allow the gesture recognizer to examine the touch object
  }
  else {
    return NO;  //NO to prevent the gesture recognizer from seeing this touch object.
  }
}

Upvotes: 3

keithbhunter
keithbhunter

Reputation: 12324

The gesture recognizer is only associated with one specific view, which means it will only recognize touches on the view it is added to. If you want to know which subview was touched, then you will need to do a couple of things:

  1. Set userInteractionEnabled = false for each subview. This will make it so that every touch on a subview is passed up to the parent view, and the touch will be recognized by the gesture recognizer.
  2. There isn't enough information on your view hierarchy or layout to know exactly how to proceed from here, but you can use one or some of these methods to determine which view was touched: UIView.hitTest(_:with:), UIView.point(inside:with:), CGRectContainsPoint() or UIGestureRecognizer.location(in:). For example, if the subviews do not overlap each other, you could use the following code snippet to test if the touch was in a particular view:

    let location = tapGesture.locationInView(parentView)
    if CGRectContainsPoint(subview1, location) {
        // subview1 was touched
    }
    

Upvotes: 3

Related Questions