如何让UICollectionViewCell子类阻止部分子视图触发didSelectItemAt:代理方法
当然可以实现!这种场景在图文混排的列表里太常见了,我来给你分享几个靠谱的实现方案,都是我实际项目里验证过的:
方案一:重写Cell的hitTest:withEvent:方法(最推荐)
这个方案完全让Cell自己掌控点击事件的流向,不需要ViewController做任何额外判断,完美符合你“Cell自行判断是否视为选中操作”的需求。
原理是:iOS的事件传递是从最上层视图往下寻找响应者,我们可以在Cell里判断点击点是否落在视频预览视图范围内,如果是,就让视频预览视图成为事件的响应者,这样Cell本身就不会接收到点击事件,自然不会触发didSelectItemAt:indexPath。
Objective-C代码示例:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 将点击点转换到视频预览视图的坐标系 CGPoint videoPreviewPoint = [self convertPoint:point toView:self.videoPreviewView]; // 判断点击是否在视频预览视图内,且该视图允许交互 if ([self.videoPreviewView pointInside:videoPreviewPoint withEvent:event] && self.videoPreviewView.userInteractionEnabled) { return self.videoPreviewView; } // 其他区域的点击,交给父类处理,正常触发Cell选中事件 return [super hitTest:point withEvent:event]; }
Swift代码示例:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let videoPreviewPoint = convert(point, to: videoPreviewView) if videoPreviewView.point(inside: videoPreviewPoint, with: event) && videoPreviewView.isUserInteractionEnabled { return videoPreviewView } return super.hitTest(point, with: event) }
这个方案的优势是封装性极强,ViewController完全不需要知道Cell内部有哪些可点击区域,所有逻辑都在Cell内部处理,后期维护也方便。
方案二:给视频预览视图添加手势识别器
如果你的视频预览视图本身就需要处理点击事件(比如点击播放视频),那这个方案更合适。我们可以给视频预览视图添加一个Tap手势,并且设置cancelsTouchesInView = true,这样当点击视频区域时,手势会拦截事件,不会传递到Cell的选中逻辑里。
Objective-C代码示例:
// 在Cell的初始化或配置方法中添加手势 - (void)setupVideoPreviewView { UITapGestureRecognizer *videoTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(videoPreviewTapped:)]; // 关键:设置为YES,拦截事件不往下传递 videoTap.cancelsTouchesInView = YES; [self.videoPreviewView addGestureRecognizer:videoTap]; } - (void)videoPreviewTapped:(UITapGestureRecognizer *)gesture { // 处理视频预览的点击逻辑,比如播放视频 }
Swift代码示例:
func setupVideoPreviewView() { let videoTap = UITapGestureRecognizer(target: self, action: #selector(videoPreviewTapped(_:))) videoTap.cancelsTouchesInView = true videoPreviewView.addGestureRecognizer(videoTap) } @objc func videoPreviewTapped(_ gesture: UITapGestureRecognizer) { // 处理视频预览的点击逻辑 }
这个方案的好处是一举两得,既处理了视频预览的点击交互,又阻止了Cell选中事件的触发,但如果视频预览不需要点击事件,只是单纯不想触发Cell选中,那方案一更简洁。
不推荐的方案:在ViewController的didSelectItemAt:里判断
虽然可以通过indexPath拿到Cell,再判断点击位置是否在视频区域,但这种方式把Cell的内部逻辑暴露给了ViewController,破坏了封装性,后期如果Cell的布局变化,ViewController也要跟着修改,维护成本很高,所以不推荐。
内容的提问来源于stack exchange,提问作者Benjohn
相关产品推荐
相关产品推荐

