如何在UITableViewCellStyleSubtitle样式的UITableViewCell对象中检测UIImageView上的触摸事件

30

我正在使用UITableViewCell对象以UITableViewCellStyleSubtitle风格(即左侧为图像视图,粗体文本标签,在此之下是详细文本标签)创建我的表格。现在我需要检测UIImageView上的触摸,并知道点击了哪个图像视图上的索引路径/单元格。我尝试使用

cell.textLabel.text = @"Sometext";
NSString *path = [[NSBundle mainBundle] pathForResource:@"emptystar1" ofType:@"png"];
UIImage *theImage = [UIImage imageWithContentsOfFile:path];
cell.imageView.image = theImage;
cell.imageView.userInteractionEnabled = YES; 

但是它没有起作用。每当单击图像时,都会调用 didSelectRowAtIndexPath:。我不想创建一个单独的 UITableViewCell 并添加一个自定义按钮。有没有办法检测 UIImageView 本身的触摸事件?

6个回答

74
在你的cellForRowAtIndexPath方法中添加这段代码。
cell.imageView.userInteractionEnabled = YES;
cell.imageView.tag = indexPath.row;

UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(myFunction:)];
tapped.numberOfTapsRequired = 1;
[cell.imageView addGestureRecognizer:tapped];   
[tapped release];

然后要检查哪个imageView被点击了,可以在selector方法中检查标志

-(void)myFunction :(id) sender
{
    UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
    NSLog(@"Tag = %d", gesture.view.tag);
}

3
在iOS 5.0版本(也可能是5.0.1),这个功能出现了问题。请查看@Andrew的答案。 - bandejapaisa
使用UILabel代替UIImageView,在iOS 5.1中可以正常工作。 - ChrisP
在imageView上设置标签将为所有单元格设置相同的值,因此如果显示了10个单元格,则它们都将获得标签值9(从零开始计数)。 - Jonathon Horsman
使用indexPath.row和标签一起发送的技巧非常棒,效果非常好。 - denikov

18

目前被接受的解决方案在 iOS 5.0 上存在问题。该 bug 导致图像视图的手势识别器永远不会被触发。通过在官方开发者论坛上进行研究,我发现这是 iOS 5.0 中已知的一个 bug。它是由内部实现引起的,导致 -gestureRecognizerShouldBegin: 返回NO。当您将手势识别器的委托设置为自定义的 UITableViewCell 子类本身时,这个 bug 就会出现。

解决方法是在手势识别器的委托中重写 -gestureRecognizerShouldBegin: 并返回YES。这个 bug 应该在未来的 iOS 5.x 版本中得到修复,只要您不使用新的 UITableViewCell 复制/粘贴 API 就是安全的。

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    return YES;
}

不错的发现!那么修复方法是提供一个委托给手势识别器,给它一个 gestureRecognizerShouldBegin: 方法,并返回 YES 吗? - Sergey Kalinichenko
@dasblinkenlight 是的,完全正确。需要注意的是,只要您不使用新的单元格复制和粘贴API,这是安全的。 - user836263
5
我已经实现了这个方法并将代理设置为自己,但是从未触发。有人知道在iOS 5.1中此问题的状态是什么吗? - serverpunk

15

对于Swift,在你的cellForRowAtIndexPath方法中添加以下代码:

cell.imageView?.userInteractionEnabled = true
cell.imageView?.tag = indexPath.row

var tapped:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "TappedOnImage:")
tapped.numberOfTapsRequired = 1
cell.imageView?.addGestureRecognizer(tapped)

然后要检查哪个imageView被点击了,请在selector方法中检查标志

func TappedOnImage(sender:UITapGestureRecognizer){
    println(sender.view?.tag)
}

这对我来说最终成为了诀窍。我的用户交互被禁用了。感谢您结束了数小时的调试 =) - Michael McKenna

6

你可以通过从图像创建一个UIImageView并向其添加手势识别器来完成此操作。请参见以下示例:

//Create ImageView
UIImageView *theImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"emptystar1.png"]];
theImageView.userInteractionEnabled = YES;

//Add Gesture Recognizer
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageSelectedInTable)];
tapped.numberOfTapsRequired = 1;
[theImageView addGestureRecognizer:tapped];
[cell addSubview:theImageView];

//Memory Cleanup
[tapped release];
[theImageView release];

-(void)imageSelectedInTable
{
    NSLog(@"Selected an Image");
}

然而,现在你需要更多地布局单元格,因为你不能简单地使用UITableViewCellUIImageView属性,因为它是只读的。


将手势识别器附加到 cell.imageView 应该可以工作。只读的 imageView 并不意味着不能在其上调用方法。 - Deepak Danduprolu
2
谢谢aahrens.. 它运行得很好.. :) 我现在唯一遇到的问题是如何知道选择了哪个图像。 有没有办法向@selector(imageSelectedInTable:)发送参数?我使用冒号检查了“id”,但它是UITapGestureRecognizer对象。 我需要包含图像视图的indexPath。 当我尝试@selector(imageSelectedInTable:indexPath)时,应用程序崩溃了.. - Shri
1
它起作用了!我只是忘记添加“imageView.userInteractionEnabled = YES;” - jovhenni19

2

我需要翻译的内容是:仅仅需要额外的信息,对于我的情况来说,我需要回答关于表格单元格中图像文件上的点击手势,因此我们需要indexPath而不是行信息,所以我决定使用被点击的图像本身而不是行信息。我为该图像定义了一个变量:

var imgSelected: UIImageView? = nil

我将手势识别器添加到了imageView(imgZona)中:
public override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier(Storyboard.CellReuseIdentifier, forIndexPath: indexPath) as! ZonasTableViewCell
    let zona = fetchedResultsController.objectAtIndexPath(indexPath) as! Zona

    cell.infoZona = zona

    let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))

    cell.imgZona?.addGestureRecognizer(tapGestureRecognizer)
    cell.imgZona?.userInteractionEnabled = true

    return cell
}

在 "imageTapped" 方法中,我检索了图像并保存到变量 "imgSelected" 中:

func imageTapped(sender: UITapGestureRecognizer) {

    imgSelected = sender.view as? UIImageView
    self.performSegueWithIdentifier("MuestraImagen", sender: self)
}

最后,在“prepareForSegue”方法中,我发送了用于显示所点击的图像的视图控制器的图像:
override public func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        switch identifier {
        case "MuestraImagen":
            if let vc = segue.destinationViewController as? MuestraImagenViewController {
                if imgSelected != nil {
                    if let img = imgSelected!.image {
                        vc.imgPuente = img
                    }
                }
            }
        default: break
        }
    }
}

0

这个问题是:

  • 将 ImageView 添加到 TableViewCell 中
  • 点击 ImageView 的事件与点击 TableViewCell 的事件不同

--> 以下代码在我这里正常工作:

cell.imageView.image = [UIImage imageNamed:@"my_image.png"];
[cell.imageView setUserInteractionEnabled:YES];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(singleTapGestureCaptured:)];    
[cell.imageView addGestureRecognizer:singleTap];

以及 "singleTapGestureCaptured" 函数

- (void)singleTapGestureCaptured:(UITapGestureRecognizer*)gesture{
    NSLog(@"Left Image clicked");
}

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