如何让UICollectionView Cell中的指定View支持点击交互?
解决UICollectionView Cell内指定View的点击交互问题
你当前代码无法触发点击事件的核心原因是:在cellForItemAt方法中,你直接替换了cell.customView.view的实例,导致之前在CollectionViewCell初始化时添加的手势识别器被覆盖掉了。下面是具体的修复方案:
步骤1:修改ScreenView的view属性逻辑
不要直接替换view实例,而是通过修改现有实例的属性来更新样式,避免丢失手势:
import UIKit class ScreenView: UIView { let rectangleView = ImageView(image: "") let maskImage = ImageView(image: "") let vectorImage = ImageView(image: "") let heading = Label(text: "Some Text", font: UIFont.systemFont(ofSize: 30, weight: .black), textColor: .black) let detailText:UILabel = { let lbl = UILabel() lbl.translatesAutoresizingMaskIntoConstraints = false lbl.font = .systemFont(ofSize: 14, weight: .light) lbl.numberOfLines = 0 return lbl }() // 将view改为不可变实例,后续只修改属性 let view = View(background: .systemPurple, cornerRadius: 12) let labelInView = Label(text: "Get Started", font: UIFont.systemFont(ofSize: 14, weight: .black), textColor: .white) init() { super.init(frame: .zero) self.translatesAutoresizingMaskIntoConstraints = false setupViews() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setupViews() { addSubview(rectangleView) rectangleView.addSubview(maskImage) rectangleView.addSubview(vectorImage) addSubview(heading) addSubview(detailText) addSubview(view) view.addSubview(labelInView) NSLayoutConstraint.activate([ rectangleView.centerYAnchor.constraint(equalTo: centerYAnchor), rectangleView.centerXAnchor.constraint(equalTo: centerXAnchor), rectangleView.widthAnchor.constraint(equalToConstant: 345), rectangleView.heightAnchor.constraint(equalToConstant: 441), maskImage.topAnchor.constraint(equalTo: rectangleView.topAnchor), maskImage.widthAnchor.constraint(equalToConstant: 345), vectorImage.bottomAnchor.constraint(equalTo: rectangleView.bottomAnchor, constant: -10), vectorImage.centerXAnchor.constraint(equalTo: rectangleView.centerXAnchor), vectorImage.widthAnchor.constraint(equalToConstant: 313), vectorImage.heightAnchor.constraint(equalToConstant: 251), heading.topAnchor.constraint(equalTo: rectangleView.bottomAnchor, constant: 20), heading.centerXAnchor.constraint(equalTo: centerXAnchor), detailText.topAnchor.constraint(equalTo: heading.bottomAnchor, constant: 20), detailText.centerXAnchor.constraint(equalTo: centerXAnchor), detailText.widthAnchor.constraint(equalToConstant: 313), view.topAnchor.constraint(equalTo: detailText.bottomAnchor, constant: 74), view.leadingAnchor.constraint(equalTo: rectangleView.leadingAnchor ), view.widthAnchor.constraint(equalToConstant: 345), view.heightAnchor.constraint(equalToConstant: 52), labelInView.centerYAnchor.constraint(equalTo: view.centerYAnchor), labelInView.centerXAnchor.constraint(equalTo: view.centerXAnchor) ]) } }
同时给View类添加属性更新方法:
class View: UIView { init(background: UIColor, cornerRadius: CGFloat) { super.init(frame: .zero) backgroundColor = background layer.cornerRadius = cornerRadius // 显式开启用户交互(默认值为true,显式声明更稳妥) isUserInteractionEnabled = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 添加属性更新方法 func update(background: UIColor, cornerRadius: CGFloat) { backgroundColor = background layer.cornerRadius = cornerRadius } }
步骤2:调整cellForItemAt中的赋值逻辑
不再替换view实例,而是调用更新方法修改其属性:
extension ViewController: UICollectionViewDelegateFlowLayout,UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return arrayData.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)as! CollectionViewCell let data = arrayData[indexPath.row] cell.customView.vectorImage.image = UIImage(named: data.vectorImages) cell.customView.maskImage.image = UIImage(named: data.maskImages) cell.customView.rectangleView.image = UIImage(named: data.rectangleImage) cell.customView.heading.text = data.headingLabel cell.customView.detailText.text = data.detailText cell.customView.labelInView.text = data.labelInView // 替换原赋值逻辑,改为更新现有view的属性 cell.customView.view.update(background: data.view.backgroundColor ?? .systemPurple, cornerRadius: data.view.layer.cornerRadius) cell.viewTapped = { [weak self] aCell in let idx = self?.collectionView.indexPath(for: aCell) print("bottomView in cell at indexPath: \(idx ?? nil) was tapped") } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 393 , height: 852) } }
步骤3:确保手势添加逻辑正确
保留CollectionViewCell的手势逻辑,同时显式开启view的用户交互:
class CollectionViewCell: UICollectionViewCell { let customView = ScreenView() var viewTapped: ((UICollectionViewCell) -> ())? override init(frame: CGRect) { super.init(frame: frame) setupView() tapOnView() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func tapOnView() { let tapView = UITapGestureRecognizer(target: self, action: #selector(handleTap)) customView.view.isUserInteractionEnabled = true customView.view.addGestureRecognizer(tapView) } func setupView() { addSubview(customView) NSLayoutConstraint.activate([ customView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -140), customView.centerXAnchor.constraint(equalTo: centerXAnchor) ]) } @objc func handleTap() { viewTapped?(self) } }
修改完成后,cell内的customView.view就能正常响应点击事件,同时样式也能正确更新。
内容的提问来源于stack exchange,提问作者Muhammad Kumail
相关产品推荐
相关产品推荐

