You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:10:32