【问题标题】:How to add UITapGestureRecognizer to an image within UICollectionViewCell如何将 UITapGestureRecognizer 添加到 UICollectionViewCell 中的图像
【发布时间】:2021-02-12 05:36:40
【问题描述】:

我的每个单元格都包含一个 imageView。目标是拥有它,以便在任何时候点击或滑动单元格(或 imageView)时,图像都会随着相应的点击或滑动动画而变化。 (点击动画缩小后扩大,而滑动动画将imageView旋转180度)

起初我在我的收藏视图的didSelectItemAt 方法中设置了我的点击功能,并且效果很好。但是,当我尝试添加滑动功能时,我发现任何用户与单元格的交互都会触发相同的点击动画。

所以,现在我正在尝试在cellForItemAt 中设置点击功能。但是,由于某种原因没有调用分接选择器。任何想法为什么?

我正在使用 UICollectionViewController。 Xcode 12,快速 5。

编辑

按照@Sandeep Bhandari 的建议,我现在正在实现一个协议,以在单元格(对点击手势具有强引用)和 UICollectionViewController 之间进行通信。但是,仍然没有调用选择器。

GameTileCell

@objc protocol GameTileCellProtocol {
     func didTapImageView(for cell: GameTileCell)
}

class GameTileCell: UICollectionViewCell {

     // other properties
     var gesture: UITapGestureRecognizer?
     weak var delegate: GameTileCellProtocol?

    override init(frame: CGRect) {
        super.init(frame: frame)
        // call configure cell method
        
        gesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        gameTileImageView.isUserInteractionEnabled = true
        gameTileImageView.addGestureRecognizer(gesture!)
        
    }
    
    // storyboard init
    // configure cell method defined
    
    @objc func handleTap(_ sender: UITapGestureRecognizer) {
        self.delegate?.didTapImageView(for: self)
        print("handleTap")
    }
}

UICollectionViewController

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GameTileCell.reuseID, for: indexPath) as! GameTileCell
        setImageAndColor(for: cell)
        cell.delegate = self
        return cell
    }
// other methods

extension GameTileCVC: GameTileCellProtocol {
func didTapImageView(for cell: GameTileCell) {
    UIView.animate(withDuration: 0.4) {
        cell.gameTileImageView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
    } completion: { (_ finished: Bool) in
        UIView.animate(withDuration: 0.4) {
            self.setImageAndColor(for: cell)
            cell.gameTileImageView.transform = CGAffineTransform.identity
        }
    }
    print(#function)
}

}

【问题讨论】:

  • 添加了新答案请检查

标签: ios swift uigesturerecognizer uicollectionviewlayout uitapgesturerecognizer


【解决方案1】:

您正在cellForItemAt indexPath: IndexPath) 方法内创建一个轻击手势识别器,这意味着它是该方法内的一个局部变量。此手势识别器的范围仅在此函数cellForItemAt indexPath: IndexPath) 内,一旦控制离开函数的范围手势识别器将被释放,因此触摸将不起作用。

您需要保持对点击手势识别器的强引用,因此我建议将此点击手势识别器从您的 ViewController 移动到 GameTileCell

因此,将您的 GameTiteCell 实现更改为类似

class GameTileCell: UICollectionViewCell {
    let gesture: UITapGestureRecognizer
    weak var delegate: GameTitleCellProtocol?
    //other declarations of yours

    override init(frame: CGRect) {
        super.init(frame: frame)
        gameTileImageView.isUserInteractionEnabled = true
        gesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        self.gameTileImageView.addGestureRecognizer(gesture)
    }

    @objc func handleTap(_ sender: UITapGestureRecognizer) {
        self.delegate?.didTapImageView(for: self)
    }
}

声明一个协议以在您的单元格和您的 ViewController 之间进行通信。让我们称之为

@objc protocol GameTitleCellProtocol {
    func didTapImageView(for cell: GameTileCell)
}

最后,让您的 ViewController 成为您的 GameTileCellcellForRowAtIndexPath 中的代表

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GameTileCell.reuseID, for: indexPath) as! GameTileCell
    setImageAndBgColor(for: cell)
    cell.delegate = self    
    return cell
}

最后让你的 ViewController 确认GameTitleCellProtocol 协议

extension YourViewController: GameTitleCellProtocol {
    func didTapImageView(for cell: GameTileCell) {
        UIView.animate(withDuration: 0.4) {
            cell.gameTileImageView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
        } completion: { (_ finished: Bool) in
            UIView.animate(withDuration: 0.4) {
                self.setImageAndBgColor(for: cell)
                cell.gameTileImageView.transform = CGAffineTransform.identity
            }
        }
    }
}

【讨论】:

  • 感谢您再次查看!我确实实施了您的建议,但仍然没有看到任何变化。我在didTapImageViewhandleTap 选择器中放置了打印语句,但都没有打印。应用不会崩溃,但点击单元格时不会发生任何事情。
  • @melh0n: 一个一个调试 1. 你在imageView上启用用户交互了吗?我已将其设置在 init 请检查是否触发了 init,是否执行了其中的语句 2.您的分接选择器是否被触发?在didTapImageView 中设置一个断点并检查控制是否到达那里? 3. 您是否将视图控制器设置为 cellForRowAtIndexPath 中的单元格委托。最后,当您说“点击单元格时没有任何反应”时,在 imageView 上添加了点击手势,我们仅调试 imageView 点击而不是单元格点击,如果单元格点击不工作,因为allowsSelection 存在
  • 设置为 false 我在之前的回答中错误地提到了
  • 我已经编辑了 OP 以包含您的建议作为实施。 1. 正在触发初始化并启用用户交互。 2.点击选择器没有被触发!控制未达到didTapImageView 3. VC 在cellForItemAt indexPath 中设置为单元格的代表,我想这就是您要说的(不是行)。
  • 正确,点击手势已添加到 imageView。我的 imageView 固定在其单元格的边缘,因此当用户点击 imageView 时,他们实际上也在点击单元格......哦,allowsSelection 目前没有设置任何内容。
【解决方案2】:

如果您想为您的单元格添加点击和滑动功能,您需要为每个单元格定义一个单独的手势识别器:

let tap = UITapGestureRecognizer(target: self, action:#selector(tapAction(_:)))
let swipe = UISwipeGestureRecognizer(target: self, action:#selector(swipeAction(_:)))
view.addGestureRecognizer(tap)
view.addGestureRecognizer(swipe)

为什么你的选择器动作没有被调用:你有没有在这一行设置断点?

if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {

我认为 if 可能不会变成积极的,因此你的行动什么也不做。

【讨论】:

  • 抱歉延迟回复!控件甚至没有到达if let indexPath 处设置的断点。我想这再次证实了我没有调用处理程序的假设:\
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 1970-01-01
相关资源
最近更新 更多