UITableView嵌套UICollectionView时didSelect代理未触发的解决方案
解决UITableViewCell嵌套UICollectionView的点击事件传递问题
问题场景
UITableView的每个Cell内嵌套了横向滚动的UICollectionView,点击UICollectionView区域时,UITableView的didSelectRowAt代理方法无法触发——原因是UICollectionView拦截了触摸事件。需要实现类似Airbnb的交互效果:保留UICollectionView的横向滚动功能,同时点击该区域能触发UITableViewCell的选中逻辑。
优雅解决方案
方法一:自定义UICollectionView透传非滚动点击事件
创建自定义UICollectionView子类,通过重写hitTest(_:with:)方法,将非滚动类的点击事件透传给父视图(UITableViewCell),同时保留滚动功能:
class PassThroughCollectionView: UICollectionView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let hitView = super.hitTest(point, with: event) // 若点击的是CollectionView本身而非内部可交互控件,透传事件给父视图 if hitView == self { return nil } return hitView } }
在TestTableViewCell中替换原UICollectionView为自定义类:
private lazy var collectionView: PassThroughCollectionView = { $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "identifier") $0.delegate = self $0.dataSource = self return $0 }(PassThroughCollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout))
方法二:通过手势代理协调多手势识别
若需要更精细的事件控制,可利用UIGestureRecognizerDelegate让UICollectionView的滚动手势与UITableView的点击手势同时生效:
- 让
TestTableViewCell遵循手势代理:
extension TestTableViewCell: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { // 允许滚动手势与UITableView的点击手势同时识别 return otherGestureRecognizer is UITapGestureRecognizer } }
- 初始化CollectionView时设置滚动手势的代理:
private lazy var collectionView: UICollectionView = { $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "identifier") $0.delegate = self $0.dataSource = self $0.panGestureRecognizer.delegate = self return $0 }(UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout))
效果验证
两种方案均可实现:点击UICollectionView区域时,UITableView的didSelectRowAt代理方法正常触发;横向滑动时,UICollectionView保持原有滚动功能,完全匹配Airbnb的交互逻辑。
内容的提问来源于stack exchange,提问作者Bejil
相关产品推荐
相关产品推荐

