将 UICollectionView 触摸事件传递给其父 UITableViewCell

Posted

技术标签:

【中文标题】将 UICollectionView 触摸事件传递给其父 UITableViewCell【英文标题】:Pass UICollectionView touch event to its parent UITableViewCell 【发布时间】:2015-11-04 01:47:08 【问题描述】:

这是视图结构:

外部视图是UITableView

UITableViewCell 内部,有一个UICollectionView。请注意,集合视图单元格之间有一些黑色间距。

当我点击 UICollectionView 中的间距时,我希望触摸事件传递给 UITableViewCell

【问题讨论】:

【参考方案1】:

@tounaobun 的出色回答。经过测试,它按预期工作:

1) 如果您点击集合视图上不是项目的任何位置,那么下面的表格单元格将被选中。

2) 如果您点击集合视图中的项目,则表格单元格将不会被选中,您可以正常与集合视图交互(也就是滚动、调用 didSelectItem 等)

我转成swift供参考:

斯威夫特 3:

class TableCellCollectionView: UICollectionView  

 override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 
    if let hitView = super.hitTest(point, with: event) 
        if hitView is TableCellCollectionView 
            return nil
         else 
            return hitView
        
     else 
        return nil
    


只需将这个类定义添加到您的代码中(我在实用程序文件中有它),然后将集合视图的类从 UICollectionView 更改为 TableCellCollectionView,您应该一切就绪。

【讨论】:

我有类似的情况:另一个 UICollectionViewCell 内部的 UICollectionViewCell。但是,我只能从包含另一个单元格的单元格中检测到点击(通过 didSelectItem 委托方法)。但我需要检测来自内部单元的水龙头。这不起作用。 @vikzilla 你找到解决方案了吗?我也有同样的问题。 @William 很好的解决方案,明白这一点的人一定会受益,因为这是解决上述问题的完美解决方案。【参考方案2】:

google了一下,找到了解决办法,继承UICollectionView类,重写hitTest:withEvent方法即可。

CustomCollectionView.h

@interface CustomCollectionView : UICollectionView

@end

CustomCollectionView.m

@implementation CustomCollectionView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

    UIView *hitView = [super hitTest:point withEvent:event];

    if ([hitView isKindOfClass:[self class]]) 
        // If it is class UICollectionView,just return nil.
        return nil;
    
    // else return super implementation.
    return [super hitTest:point withEvent:event];


@end

【讨论】:

【参考方案3】:

最高投票答案的代码可以轻松缩短。

斯威夫特 4.1:

final class InteractiveCollectionView: UICollectionView 
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 
        return super.hitTest(point, with: event) as? InteractiveCollectionView
    

【讨论】:

这种简化是错误的,CollectionView 命中应该返回nil。但是,此代码返回的是找到的 CollectionView,因此不允许父级处理点击。【参考方案4】:

您可以覆盖UICollectionViewpoint(inside:with:)方法,并手动检查是否有任何单元格包含指定点:

class CollectionView: UICollectionView 
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool 
        visibleCells.contains(where:  $0.frame.contains(point) )
    

【讨论】:

【参考方案5】:

是否可以将collectionView的backgroundView UserInteraction设置为不启用,但确保collectionViewCell启用,以便它可以将tapEvent传递给下一个响应者。

- (void)viewDidLoad 
    theCollectionView.userInteractionEnabled = NO;

我希望它会有所帮助。

【讨论】:

这样 UICollectionViewCell 无法响应用户交互。

以上是关于将 UICollectionView 触摸事件传递给其父 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章

如何将触摸事件传递给 parentViewController?

滚动 UICollectionView 时忽略嵌入式 UIButtons 的触摸事件

将触摸事件传递给多个选项之一

将触摸事件传递给父视图

将触摸事件传递给 iOS 状态栏

仅当触摸类型为手指时,如何将触摸事件传递给其他视图?