Swift:UICollectionViewCell嵌套子视图多触摸事件触发问题
解决UICollectionViewCell嵌套UIView的触摸事件问题
看起来你遇到的是自定义Cell内嵌套View的事件传递和触发问题,我来给你一步步拆解解决方案:
先排查基础配置问题
首先确保最基础的交互开关是打开的:
- 确认两个嵌套的UIView的
isUserInteractionEnabled属性设为true(默认是true,但如果手动修改过要改回来) - 确认删除按钮这类UIControl控件的
isUserInteractionEnabled也是true(按钮默认是开启的,但如果被意外关闭需要恢复) - 检查CollectionViewCell的
selectionStyle,如果设为.none不影响内部事件,但如果有自定义手势要注意冲突
用闭包/代理实现Cell内部事件回调
因为Cell内的事件需要传递给ViewController处理,最简洁的方式是用闭包(或者代理模式,看个人习惯),下面是具体实现:
第一步:自定义CollectionViewCell类
给Cell里的嵌套View和按钮添加事件回调闭包:
class CustomCollectionViewCell: UICollectionViewCell { // 假设你的两个嵌套View叫viewA、viewB,删除按钮叫trashBtnA、trashBtnB @IBOutlet weak var viewA: UIView! @IBOutlet weak var viewB: UIView! @IBOutlet weak var trashBtnA: UIButton! @IBOutlet weak var trashBtnB: UIButton! // 定义回调闭包 var onViewATap: (() -> Void)? var onViewBTap: (() -> Void)? var onTrashBtnATap: (() -> Void)? var onTrashBtnBTap: (() -> Void)? override func awakeFromNib() { super.awakeFromNib() setupInteractions() } private func setupInteractions() { // 给嵌套View添加点击手势 let tapA = UITapGestureRecognizer(target: self, action: #selector(viewATapped)) viewA.addGestureRecognizer(tapA) let tapB = UITapGestureRecognizer(target: self, action: #selector(viewBTapped)) viewB.addGestureRecognizer(tapB) // 给删除按钮绑定点击事件 trashBtnA.addTarget(self, action: #selector(trashBtnATapped), for: .touchUpInside) trashBtnB.addTarget(self, action: #selector(trashBtnBTapped), for: .touchUpInside) } // 事件触发时调用闭包 @objc private func viewATapped() { onViewATap?() } @objc private func viewBTapped() { onViewBTap?() } @objc private func trashBtnATapped() { onTrashBtnATap?() } @objc private func trashBtnBTapped() { onTrashBtnBTap?() } // 根据条件切换显示/隐藏嵌套View func setupDisplay(with condition: Bool) { viewA.isHidden = !condition viewB.isHidden = condition } }
第二步:在ViewController中绑定回调
在cellForItemAt方法里给Cell的闭包赋值,处理具体业务逻辑:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCollectionViewCell // 传入你的显示条件 let shouldShowViewA = // 你的条件判断逻辑 cell.setupDisplay(with: shouldShowViewA) // 绑定View点击回调 cell.onViewATap = { [weak self] in guard let self = self else { return } let item = self.dataSource[indexPath.item] print("View A 被点击,对应数据:\(item)") // 这里写你的View A点击后的业务逻辑 } cell.onViewBTap = { [weak self] in guard let self = self else { return } let item = self.dataSource[indexPath.item] print("View B 被点击,对应数据:\(item)") // 这里写你的View B点击后的业务逻辑 } // 绑定删除按钮回调 cell.onTrashBtnATap = { [weak self] in guard let self = self else { return } self.dataSource.remove(at: indexPath.item) self.collectionView.deleteItems(at: [indexPath]) } cell.onTrashBtnBTap = { [weak self] in guard let self = self else { return } self.dataSource.remove(at: indexPath.item) self.collectionView.deleteItems(at: [indexPath]) } return cell }
解决手势冲突问题
如果出现点击删除按钮时,同时触发了嵌套View的点击事件,需要给手势添加代理,过滤按钮区域的触摸:
在CustomCollectionViewCell里扩展代理方法:
extension CustomCollectionViewCell: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { // 判断触摸点是否在删除按钮上,是则不触发View的手势 if gestureRecognizer.view == viewA { return touch.view != trashBtnA } else if gestureRecognizer.view == viewB { return touch.view != trashBtnB } return true } }
然后在setupInteractions里给手势设置代理:
tapA.delegate = self tapB.delegate = self
这样就能保证点击删除按钮时只触发按钮事件,点击View其他区域时触发View的点击事件了。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

