检测 UITableViewCell 子视图内的触摸

Posted

技术标签:

【中文标题】检测 UITableViewCell 子视图内的触摸【英文标题】:Detecting touch inside UITableViewCell subview 【发布时间】:2014-07-23 15:46:02 【问题描述】:

我不清楚应该在哪里将 UIGestureRecognizer 代码添加到 UITableViewCell 的相应子视图中。我已经阅读了我能找到的所有相关问题。现在我的单元格和单元格的子视图在 cellForRowAtIndexPath 内生成。我试图在 cellForRowAtIndexPath 中添加手势:

UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[mySubview addGestureRecognizer:tapGesture];
tapGesture.cancelsTouchesInView = YES;
tapGesture.delegate = self;

但是,这并没有检测到任何东西。为了验证我的 UIGesture 识别器是否正常工作,我在 tableView 本身上使用了上面的代码,它确实按预期注册了触摸。此外,当 tableView 附加了上述手势时,也会按预期调用以下代码:

-(BOOL) gestureRecognizer:(UITapGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

    NSLog(@"shouldRevceiveTouch");
    return YES;


- (BOOL)gestureRecognizer:(UITapGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UITapGestureRecognizer *)otherGestureRecognizer 

    NSLog(@"simultaneously");
    return YES;

我试图从 tableView 和 cellForRowAtIndexPath 内部删除 GestureRecognizer 我试图将 GestureRecognizer 附加到单元格本身,它的任何子视图,没有检测到任何其他内容。 (以上代码均未触发)

显然我错误地添加了 GestureRecognizer。在哪里/何时是添加 GestureRecognizer 的合适位置/时间?

谢谢。

【问题讨论】:

我认为如果 mySubview 不是 nil 并且它的 userInteractionEnabled 属性设置为 yes,您显示的代码应该可以工作。 mySubview 是什么类型的视图? 如果子视图是 UILabel 类型,请启用 userInteraction 属性为 true。 【参考方案1】:

我做过类似的事情,但它是UILongPressGestureRecognizer。我认为没有太大的区别(因为所有的触摸都是由UITableView 接收的)。我在控制器 viewDidLoad 方法中添加了手势识别器(不在单元格中)。

- (void) tableViewLongPress:(UILongPressGestureRecognizer *)gestureRecognizer 
    CGPoint p = [gestureRecognizer locationInView:self.messageTableView];

    NSIndexPath *indexPath = [self.messageTableView indexPathForRowAtPoint:p];
    if (indexPath == nil)
        NSLog(@"long press on table view but not on a row");
    else 
        UITableViewCell *cell = [self.messageTableView cellForRowAtIndexPath:indexPath];
        CGPoint pointInCell = [cell convertPoint:p fromView:self.messageTableView];
    

你可以把长按换成普通的,自己试试

【讨论】:

谢谢,我决定走这条路。在检测该点是否在视图框架中时,我现在遇到了一个单独的问题。如果我单击框架的上半部分,并且在框架上方一点,就会检测到该点。现在正在努力。 @tpdietz 我认为您可以尝试将点转换为单元坐标空间,但转换为所需的 UIView。【参考方案2】:

我需要检测对单元格内不同子视图的触摸。还处理 ios 9 的 UITableViewCellContentView

首先,我在自定义 UITableViewCell

中覆盖了 touchesBegan
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:touch.view];

    // Imagine I have 2 labels inside my cell
    CGPoint convertedPoint = [self.firstLabel convertPoint:point fromView:touch.view];
    if ([self.firstLabel pointInside:convertedPoint withEvent:nil]) 
        // Touched first label
        return;
     

    convertedPoint = [self.secondLabel convertPoint:point fromView:touch.view];
    if ([self.secondLabel pointInside:convertedPoint withEvent:nil]) 
        // Touched second label
        return;
     

    // no labels touched, call super which will call didSelectRowAtIndexPath
    [super touchesBegan:touches withEvent:event];

为了修复 iOS 9 中的支持,我们应该覆盖 awakeFromNib 或者如果单元格不在 Storyboard / xib 中,则只禁用单元格用户交互:

- (void)awakeFromNib 
    // Initialization code
    self.contentView.userInteractionEnabled = NO;
 

当然,我们不应该忘记启用标签用户交互。

【讨论】:

【参考方案3】:

不确定您到底要做什么。如果您只想检测用户是否点击了表格中的单元格,那么您不需要实现手势识别器。只需实现下面的委托方法来检测何时选择了表中的,然后处理该行的元素,例如获取子视图等。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
   // Do all my cool tap related stuff here for example, get the row that was tapped:
   UITableViewCell *cell= [tableView cellForRowAtIndexPath:indexPath];
   // get your subview (assume its a UIImageView) from cell - one way to do it below
   UIImageView photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];

如果您进一步描述您的问题,那么也许我可以提供其他建议。

【讨论】:

以上是关于检测 UITableViewCell 子视图内的触摸的主要内容,如果未能解决你的问题,请参考以下文章

忽略UITableViewCell内的垂直滚动

UITableViewCell 内的 UIScrollView - 水平滚动

iOS 增加 UITableViewCell 中 UIButton 的触控区域

无法获取 UITableViewCell 的索引路径

UITableViewCell 内的多个堆栈视图内的多行标签

自动布局:无法弄清楚如何解决与扩展 UITableViewCell 内的面板相关的警告