如何将UITapGestureRecognizer添加到表视图单元格内的UILabel?

24

我正在使用 NIB 文件布局自定义的表格视图单元格。这个单元格有一个名为 lblName 的插座标签。将 UITapGestureRecognizer 添加到该标签上从未触发相关事件。我已经将 userInteractionEnabled 设置为 YES。

我猜问题是 UILabel 在 TableView 中,而表格/单元格视图正在拦截点击事件。我能做些什么吗?

我只想在按下 UILabel 时执行一些自定义操作!我看到的所有解决方法都很荒谬。使用标准工具集应该很容易。但显然不是这样。

这是我使用的代码:

- (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];
}
10个回答

23

简单方法:

您还可以在该标签顶部使用一个不可见按钮。这样,您就可以减少添加tapGesture的工作量。

备选方法:

您不应为该UILabel创建IBOutlet。这样做会在自定义类实现文件中添加一个outlet。无法在其他文件中访问它。因此,在自定义类IB中为该标签设置一个标记,并在cellForRowAtIndexPath:方法中编写代码。

更新:

cellForRowAtIndexPath:方法中,

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];
    }
}

谢谢,这个解决了问题!不过你的代码中有几个错别字:首先,“if” 应该改为 “for”,然后你想要枚举 cell.contentViews.subviews。感谢你的回答! - Bryan
哦,我在这里自己打的。所以有一些小错误。不管怎样,我会更新它的。 - Dinesh Raja
4
在我设置了单元格本身的“启用用户交互”之前,这对我没有起作用。 - Nemanja Kovacevic
这些解决方案存在问题,当重复使用特定单元格时会发生什么? - Ratul Sharker
“简单的方法”实际上是最酷的,至少在我的情况下,因为我想要扩大点击区域并使其形状与标签不同。点赞。 - Eir

14
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)]; 
[recognizer setNumberOfTapsRequired:1];
lblName.userInteractionEnabled = YES;  
[lblName addGestureRecognizer:recognizer];

1
需要将userInteractionEnabled属性设置为YES。在我的情况下,标签位于另一个视图内,如果不设置此属性,则手势无法正常工作。 - alcamla

9

这样做没有问题:

- (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;
      ....
     }
}

即使使用IB创建UILabel的情况下,也可以进行以下操作。

这会对他有所帮助。但是他需要在UITableViewCell内部创建一个带有Tap手势的标签。 - Dinesh Raja
在创建单元格的方法中,当您创建一个UITapGestureRecognizer时,请给它一个标签,并在处理程序中管理事件以区分标签。 - WhiteTiger
在cellForRowAtIndexPath:方法中。... UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)]; tap.tag = [NSIndexPath row]; ... 处理方法:- (void)tapAction:(id)sender { switch(((UITapGestureRecognizer *)sender).tag) { case 0:NSLog(@"Tap action 1"); break; case 1:NSLog(@"tap action 2");break; ..... } - WhiteTiger
给手势添加标签有什么用处?这不是大问题。而且你必须将你的标签作为单元格的子视图添加,而不是父视图。 - Dinesh Raja
2
如果我理解正确,您希望在单元格点击时执行某个特定操作,对吗?那么一个想法可能是为每个单元格(其中包含标签)设置一个tapGesture事件,分配一个与单元格编号相对应的标记,这样当您点击标签时,就可以准确地知道您所基于的标记点击了哪个单元格。然后您可以可能以更复杂的方式进行管理,但这仍然是您问题的起点。 - WhiteTiger
显示剩余2条评论

7
您可以使用以下代码在UITableView单元格中的UILable上添加触摸手势:
UITapGestureRecognizer *tapGeature = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(lblClick:)];
tapGeature.delegate =self;
tapGeature.numberOfTapsRequired = 1;

cell.lbl.userInteractionEnabled = YES;
[cell.lbl addGestureRecognizer:tapGeature];

并且需要访问选择器方法
- (void)lblClick:(UITapGestureRecognizer *)tapGesture {
    UILabel *label = (UILabel *)tapGesture.view;
    NSLog(@"Lable tag is ::%ld",(long)label.tag);
}

对于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)")
}

5

根据Hardik Thakkar的解决方案,基于Swift 5的2019年更新。要检测单元格中UILabel上的点击,请在下面的视图控制器中查找cellForRowAt方法。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

请在返回单元格之前将以下代码放入以上方法中:
let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(labelTap(tapGesture:)))
tapGesture.delegate = self
tapGesture.numberOfTapsRequired = 1
cell.yourLabel.isUserInteractionEnabled = true
cell.yourLabel.tag = indexPath.row
cell.yourLabel.addGestureRecognizer(tapGesture)            
return cell

为您的视图控制器添加一个处理点击的方法:

@objc func labelTap(tapGesture:UITapGestureRecognizer){
    print("Label tag is:\(tapGesture.view!.tag)")
}

1

对于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)

然后

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

1
你可以在单元格的 -awakeFromNib 方法中添加以下代码。
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognizerAction:)];
[self.yourLabel setUserInteractionEnabled:YES];
[self.yourLabel addGestureRecognizer:gesture];

1

一旦您将轻拍手势分配给UILabel并启用用户交互,在回调函数中,您可以通过搜索superviews的嵌套来查找单元格视图中的indexpath:

- (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;
}

0
对于Swift,您可以在cellForRowAtIndexPath方法内添加此代码。
var tap = UITapGestureRecognizer(target: self, action: "labelTapped")
tap.numberOfTapsRequired = 1
cell.label.addGestureRecognizer(tap)
cell.label.tag = indexPath.row

然后执行操作

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

    // Do whatever you want.
}

1
OP提出了一个Objective-C的问题,而不是Swift。 - David Hoelzer
1
你所拥有的会导致运行时错误。action: "labelTapped" 表示该方法期望在没有任何参数的情况下被调用,但是该方法的签名却表明了相反的情况。 - maml
表视图单元格会被重用; 那么是否有将手势识别器多次添加到同一单元格的风险呢?(相同的问题也适用于包含在单元格中的按钮中的addTarget:action:forControlEvents:方法。) - Nicolas Miari

0

Dinesh建议的方法可以使用属性变量而无需使用for循环来实现。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接