如何为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与业务逻辑耦合:
- 定义代理协议
protocol ListCellDelegate: AnyObject { func didTapFeaturedImageView(in cell: ListCell) }- 在Cell中添加代理属性并修改点击方法
class ListCell: UITableViewCell { weak var delegate: ListCellDelegate? @objc func pressed() { delegate?.didTapFeaturedImageView(in: self) } }- 在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)的图片") } }- 在
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
相关产品推荐
相关产品推荐

