如何将 UITapGestureRecognizer 添加到 UICollectionViewCell 中的图像

问题描述

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

起初,我在集合视图的 body: _currentPosition == null ? Center( child: Row( mainAxisAlignment: MainAxisAlignment.center,children: [ SizedBox( height: 20.0,width: 20.0,child: CircularProgressIndicator(),),SizedBox( width: 10.0,Text("Getting your location..."),],) : Column( ... 方法中设置了点按功能,并且效果很好。但是,当我尝试添加滑动功能时,我发现任何用户与单元格的交互都会触发相同的点击动画

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

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

编辑

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

GameTileCell

cellForItemAt

UICollectionViewController

@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")
    }
}

}

解决方法

您正在 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
            }
        }
    }
}
,

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

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 可能不会变成积极的,因此你什么都不做就离开了。