如何检测UICollectionViewCell长按并显示图片遮罩层
解决UICollectionViewCell长按不显示遮罩层的问题
问题根源
- 手势Target设置错误:你在
cellForItemAt中创建长按手势时,target传的是MyCollectionCell()(新实例),而非当前复用的cell实例。这导致长按触发的是未显示的新cell方法,屏幕上的cell遮罩层不会有变化。 - 手势添加时机不合理:每次复用cell都移除所有手势再添加,操作冗余且易引发问题,应在cell内部初始化时统一添加手势。
- 未处理手势结束状态:仅处理了
began状态显示遮罩,未处理ended/cancelled状态隐藏遮罩,用户体验不完整。
修复后的代码
1. 修改MyCollectionCell类
class MyCollectionCell: UICollectionViewCell { weak var textLabel: UILabel! let movieImage: UIImageView = { let image = UIImageView() image.translatesAutoresizingMaskIntoConstraints = false image.clipsToBounds = true image.contentMode = .scaleAspectFill image.layer.cornerRadius = 10 return image }() let movieOverlay: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .black.withAlphaComponent(0.7) view.alpha = 0 return view }() override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(movieImage) movieImage.addSubview(movieOverlay) // 在cell内部添加长按手势,target指向当前cell实例 let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(directFullPreviewLongPressAction(g:))) addGestureRecognizer(longPressGesture) NSLayoutConstraint.activate([ movieImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10), movieImage.topAnchor.constraint(equalTo: contentView.topAnchor), movieImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10), movieImage.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), movieOverlay.leadingAnchor.constraint(equalTo: movieImage.leadingAnchor), movieOverlay.topAnchor.constraint(equalTo: movieImage.topAnchor), movieOverlay.trailingAnchor.constraint(equalTo: movieImage.trailingAnchor), movieOverlay.bottomAnchor.constraint(equalTo: movieImage.bottomAnchor) ]) } override func prepareForReuse() { super.prepareForReuse() movieImage.image = nil // 复用cell时重置遮罩状态 movieOverlay.alpha = 0 } func configure(with urlString: String){ movieImage.sd_setImage(with: URL(string: urlString), placeholderImage: UIImage(named: "ImagePlaceholder")) } @objc func directFullPreviewLongPressAction(g: UILongPressGestureRecognizer) { switch g.state { case .began: // 长按开始,显示遮罩(添加动画提升流畅度) UIView.animate(withDuration: 0.2) { self.movieOverlay.alpha = 1 } case .ended, .cancelled, .failed: // 长按结束/取消/失败,隐藏遮罩 UIView.animate(withDuration: 0.2) { self.movieOverlay.alpha = 0 } default: break } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
2. 简化cellForItemAt方法
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseMyCellID, for: indexPath) as! MyCollectionCell cell.tag = indexPath.row // 配置cell数据 cell.configure(with: yourImageUrlArray[indexPath.row]) return cell }
修复要点
- 将手势target改为
self,确保触发当前显示cell的方法。 - 在cell初始化阶段添加手势,避免复用cell时重复操作。
- 为遮罩的显示/隐藏添加动画,提升交互流畅度。
- 复用cell时重置遮罩状态,避免旧状态残留。
内容的提问来源于stack exchange,提问作者KwameB
相关产品推荐
相关产品推荐

