How can I add a UITapGestureRecognizer to a UILabel inside a table view cell?

I am using a NIB file to layout a custom table view cell. This cell has a label with outlet called lblName. Adding a UITapGestureRecognizer to this label never fires the associated event. I have userInteractionEnabled = YES.

I’m guessing that the problem is that the UILabel is in a TableView and that the table/cell view is intercepting the taps. Can I do something about this?

  • wrong frame size in viewDidLoad
  • UIButton as switch
  • ios swift share-extension: what are all and the best ways to handle images?
  • iOS 9 how get locations even if app terminated
  • How to make appium tests run faster on iOS?
  • UIPageViewController Gesture recognizers
  • All I want to do is perform some custom action when a UILabel is pressed! All of the solutions for doing this that I’ve seen are ridiculous. It should be easy using the standard tool set. But evidently not.

    Here’s the code I’m using:

    - (void)tapAction {
        NSLog(@"Tap action");
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib
    
        UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)]; 
        [recognizer setNumberOfTapsRequired:1];
        //lblName.userInteractionEnabled = true;  (setting this in Interface Builder)
        [lblName addGestureRecognizer:recognizer];
    }
    

    9 Solutions Collect From Internet About “How can I add a UITapGestureRecognizer to a UILabel inside a table view cell?”

    EASY WAY:

    You may also use a invisible button on the top of that label. So it will reduce your work of adding tapGesture for that label.

    ALTERNATIVE WAY:

    You should not create an IBOutlet for that UILabel. When you do that,you will add a outlet in custom class implementation file. You cannot access in other file. So set a tag for that label in custom class IB and write a code in cellForRowAtIndexPath: method.

    UPDATED:

    In cellForRowAtIndexPath: method,

    for(UIView *view in cell.contentViews.subviews) {
        if(view.tag == 1) {
            UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
            [tap setNumberOfTapsRequired:1];
            [view addGestureRecognizer:tap];
        }
    }
    
    UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)]; 
    [recognizer setNumberOfTapsRequired:1];
    lblName.userInteractionEnabled = YES;  
    [lblName addGestureRecognizer:recognizer];
    

    Doing this works without problems:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    {
       ...
       // create you cell
       UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
       [lbl setText:@"example"];
       [lbl setUserInteractionEnabled:YES];
       [cell.contentView addSubview:lbl];
       UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self    action:@selector(tapAction:)];
       tap.tag = [NSIndexPath row];
       [tap setNumberOfTapsRequired:1];
       [lbl addGestureRecognizer:tap];
       ... 
    }
    
    - (void)tapAction:(id)sender {
      switch(((UITapGestureRecognizer *)sender).view.tag) {
         case 0:
              // code
              break;
         case 1:
             // code
             break;
          ....
         }
    }
    

    even in the case in which creates the UILabel with IB

    You can use below code to add tap gesture on UILable in UITableView cell

    UITapGestureRecognizer *lblAction = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(lblClick:)];
    lblAction.delegate =self;
    lblAction.numberOfTapsRequired = 1;
    cell.lbl.userInteractionEnabled = YES;
    [cell.lbl addGestureRecognizer:lblAction];
    

    and to access the selector method

    - (void)lblClick:(UITapGestureRecognizer *)tapGesture {
        UILabel *label = (UILabel *)tapGesture.view;
        NSLog(@"Lable tag is ::%ld",(long)label.tag);
    }
    

    For Swift

    let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(lblClick(tapGesture:)))
    tapGesture.delegate = self
    tapGesture.numberOfTapsRequired = 1
    cell.lbl.userInteractionEnabled = true
    cell.lbl.tag = indexPath.row
    cell.lbl.addGestureRecognizer(tapGesture)
    
    func lblClick(tapGesture:UITapGestureRecognizer){
       print("Lable tag is:\(tapGesture.view!.tag)")
    }
    

    Once you assign the tap gesture to the UILabel and set the user interaction to enabled, in your callback function you can find the indexpath from the cell view but searching through the nest of superviews:

    - (UITableViewCell *) findCellInSuperview:(UIView *)view
    {
    UITableViewCell *cell = nil;
    
        NSString *className = NSStringFromClass([[view superview] class]);
        if ([className isEqualToString:@"UITableViewCell"]) {
            cell = (UITableViewCell *)[view superview];
        } else {
            if ([view superview] != nil) {
                cell = [self findCellInSuperview:[view superview]];
            }
        }
    
    return cell;
    }
    

    The way Dinesh suggested will work without the for loop using the property variable.

    UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
    [tap setNumberOfTapsRequired:1];
    [self.myUILabel addGestureRecognizer:tap];
    

    You can add next in your cell’s -awakeFromNib method

    UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognizerAction:)];
    [self.yourLabel setUserInteractionEnabled:YES];
    [self.yourLabel addGestureRecognizer:gesture];
    

    For Swift,
    you can add this inside your cellForRowAtIndexPath method.

    var tap = UITapGestureRecognizer(target: self, action: "labelTapped")
    tap.numberOfTapsRequired = 1
    cell.label.addGestureRecognizer(tap)
    cell.label.tag = indexPath.row
    

    Then for action

    func labelTapped(gesture: UITapGestureRecognizer) {
        let indexPath = NSIndexPath(forRow: gesture.view!.tag, inSection: 0)
        let cell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
    
        // Do whatever you want.
    }
    

    For Swift 3

    let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: 
    #selector(lblClick(tapGesture:)))
    tapGesture.delegate = self
    tapGesture.numberOfTapsRequired = 1
    cell.lbl.isUserInteractionEnabled = true
    cell.lbl.tag = indexPath.row
    cell.lbl.addGestureRecognizer(tapGesture)
    

    And then

    func lblClick(tapGesture:UITapGestureRecognizer){
        print("Lable tag is:\(tapGesture.view!.tag)")
    }