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

如何为UITableViewCell内的UIImageView添加点击事件?

UITableViewCell内部元素点击事件失效的解决方案

问题描述

我希望为UITableViewCell内的元素添加点击事件,查阅资料后给UIImageView设置了isUserInteractionEnabled = true以允许它接收点击事件,同时为UITapGestureRecognizer设置cancelsTouchesInView = true来阻止事件传递给Cell,但这个方案没有生效,求指导如何实现Cell内对象的点击事件。

测试示例代码:

import UIKit
import SnapKit

class ViewController: UIViewController {
    
    var list: [dao] = [dao]()
    
    private lazy var tableView: UITableView = {
        let view = UITableView()
        view.estimatedRowHeight = 44
        view.rowHeight = UITableView.automaticDimension
        
        view.register(ListCell.self, forCellReuseIdentifier: "listCell")
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = self
        
        list.append(dao(featured: "featured1", name: "featured1"))
        list.append(dao(featured: "featured2", name: "featured2"))
        
        self.view.addSubview(tableView)
        tableView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.top.equalToSuperview()
            make.bottom.equalToSuperview()
        }
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath) as? ListCell {
            let row: dao = self.list[indexPath.row]
            cell.update(row: row, idx: indexPath.row + 1)
            return cell
        }
        return UITableViewCell()
    }
}

class ListCell: UITableViewCell {
    
    let featruedIV: UIImageView = {
        let view: UIImageView = UIImageView()
        view.contentMode = .scaleAspectFill
        view.layer.cornerRadius = 6
        view.clipsToBounds = true
        view.isUserInteractionEnabled = true
        
        return view
    }()
    
    let nameLbl: UILabel = {
        let view = UILabel()
        
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.setupView()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        setupView()
    }
    
    private func setupView() {
        
        self.addSubview(featruedIV)
        featruedIV.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.left.equalToSuperview().offset(12)
            make.bottom.equalToSuperview().offset(-12)
            make.height.width.equalTo(90)
        }
        
        let tg: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(pressed))
        tg.cancelsTouchesInView = true
        featruedIV.addGestureRecognizer(tg)
        
        self.addSubview(nameLbl)
        nameLbl.snp.makeConstraints { make in
            make.centerY.equalTo(featruedIV.snp.centerY)
            make.left.equalTo(featruedIV.snp.right).offset(12)
        }
    }
    
    func update(row: dao, idx: Int) {
        nameLbl.text = row.name
        featruedIV.image = UIImage(named: row.featured)
    }
    
    @objc func pressed() {
        print("pressed")
    }
}

class dao {
    var featured: String
    var name: String
    
    init(featured: String, name: String) {
        self.featured = featured
        self.name = name
    }
}

解决步骤

  • 移除重复的视图初始化逻辑:你的setupView()在init、required init和awakeFromNib中都被调用,导致UIImageView被重复添加手势,引发事件冲突。删除awakeFromNib中的setupView()调用即可。
  • 验证手势基础有效性:先暂时去掉tg.cancelsTouchesInView = true,测试手势是否能正常触发pressed()方法。确认手势生效后,再根据需求添加该属性控制事件传递。
  • 确保Cell用户交互未被禁用:UITableViewCell默认isUserInteractionEnabled为true,若代码中意外设置为false会阻断子视图的事件响应,检查Cell的该属性状态。
  • 推荐使用代理解耦事件处理(可选):如果希望在ViewController中处理点击事件而非Cell内部,可以通过代理模式实现,避免Cell与业务逻辑耦合:
    1. 定义代理协议
    protocol ListCellDelegate: AnyObject {
        func didTapFeaturedImageView(in cell: ListCell)
    }
    
    1. 在Cell中添加代理属性并修改点击方法
    class ListCell: UITableViewCell {
        weak var delegate: ListCellDelegate?
        
        @objc func pressed() {
            delegate?.didTapFeaturedImageView(in: self)
        }
    }
    
    1. 在ViewController中实现代理
    extension ViewController: ListCellDelegate {
        func didTapFeaturedImageView(in cell: ListCell) {
            guard let indexPath = tableView.indexPath(for: cell) else { return }
            let item = list[indexPath.row]
            print("点击了\(item.name)的图片")
        }
    }
    
    1. 在cellForRowAt中设置代理
    cell.delegate = self
    

修正后的完整代码示例

import UIKit
import SnapKit

protocol ListCellDelegate: AnyObject {
    func didTapFeaturedImageView(in cell: ListCell)
}

class ViewController: UIViewController {
    
    var list: [dao] = [dao]()
    
    private lazy var tableView: UITableView = {
        let view = UITableView()
        view.estimatedRowHeight = 44
        view.rowHeight = UITableView.automaticDimension
        
        view.register(ListCell.self, forCellReuseIdentifier: "listCell")
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = self
        
        list.append(dao(featured: "featured1", name: "featured1"))
        list.append(dao(featured: "featured2", name: "featured2"))
        
        self.view.addSubview(tableView)
        tableView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.top.equalToSuperview()
            make.bottom.equalToSuperview()
        }
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath) as? ListCell else {
            return UITableViewCell()
        }
        let row = list[indexPath.row]
        cell.update(row: row, idx: indexPath.row + 1)
        cell.delegate = self
        return cell
    }
}

extension ViewController: ListCellDelegate {
    func didTapFeaturedImageView(in cell: ListCell) {
        guard let indexPath = tableView.indexPath(for: cell) else { return }
        let item = list[indexPath.row]
        print("点击了\(item.name)的图片")
    }
}

class ListCell: UITableViewCell {
    
    weak var delegate: ListCellDelegate?
    
    let featruedIV: UIImageView = {
        let view = UIImageView()
        view.contentMode = .scaleAspectFill
        view.layer.cornerRadius = 6
        view.clipsToBounds = true
        view.isUserInteractionEnabled = true
        
        return view
    }()
    
    let nameLbl: UILabel = {
        let view = UILabel()
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // 移除重复的setupView调用
    }
    
    private func setupView() {
        contentView.addSubview(featruedIV)
        featruedIV.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.left.equalToSuperview().offset(12)
            make.bottom.equalToSuperview().offset(-12)
            make.height.width.equalTo(90)
        }
        
        let tg = UITapGestureRecognizer(target: self, action: #selector(pressed))
        // 先测试时可注释,确认生效后再打开
        // tg.cancelsTouchesInView = true
        featruedIV.addGestureRecognizer(tg)
        
        contentView.addSubview(nameLbl)
        nameLbl.snp.makeConstraints { make in
            make.centerY.equalTo(featruedIV.snp.centerY)
            make.left.equalTo(featruedIV.snp.right).offset(12)
        }
    }
    
    func update(row: dao, idx: Int) {
        nameLbl.text = row.name
        featruedIV.image = UIImage(named: row.featured)
    }
    
    @objc func pressed() {
        delegate?.didTapFeaturedImageView(in: self)
    }
}

class dao {
    var featured: String
    var name: String
    
    init(featured: String, name: String) {
        self.featured = featured
        self.name = name
    }
}

内容的提问来源于stack exchange,提问作者ives

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:09:54