简体   繁体   English

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

[英]How to add UITapGestureRecognizer to an image within UICollectionViewCell

Each of my cell's contain one imageView.我的每个单元格都包含一个 imageView。 The goal is to have it so that any time the cell (or imageView) is tapped or swiped the image changes with the corresponding tap or swipe animation.目标是让任何时候点击或滑动单元格(或 imageView),图像都会随着相应的点击或滑动 animation 发生变化。 (The tap animation shrinks and then expands, while the swipe animation rotates the imageView 180 degrees) (水龙头 animation 收缩然后膨胀,而滑动 animation 将 imageView 旋转 180 度)

At first I set up my tap functionality in my collection view's didSelectItemAt method and this worked fine.起初,我在我的集合视图的didSelectItemAt方法中设置了我的点击功能,并且效果很好。 But, when I tried to add the swipe functionality I found that any user interaction with the cell would trigger the same tap animation.但是,当我尝试添加滑动功能时,我发现任何用户与单元格的交互都会触发相同的点击 animation。

SO, now I'm trying to set up the tap functionality in cellForItemAt .所以,现在我正在尝试在cellForItemAt中设置点击功能。 However, the tap selector for some reason is not being called.但是,由于某种原因没有调用分接选择器。 Any ideas why?任何想法为什么?

I am using a UICollectionViewController.我正在使用 UICollectionViewController。 Xcode 12, swift 5. Xcode 12,swift 5。

EDIT编辑

Following @Sandeep Bhandari's suggestions I am now implementing a protocol to communicate between the cell (which holds a strong ref to the tap gesture) and UICollectionViewController.遵循@Sandeep Bhandari 的建议,我现在正在实现一个协议以在单元格(它对点击手势具有强引用)和 UICollectionViewController 之间进行通信。 However, selector is still not being called.但是,仍然没有调用选择器。

GameTileCell 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 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)
}

} }

You are creating a tap gesture recognizer inside a cellForItemAt indexPath: IndexPath) method which means its a local variable inside this method.您正在cellForItemAt indexPath: IndexPath)方法内创建轻击手势识别器,这意味着它是此方法内的局部变量。 Scope of this gesture recognizer is only inside this function cellForItemAt indexPath: IndexPath) as soon as control leaves the function's scope gesture recognizer will be deallocated and hence touch wouldn't work.此手势识别器的 Scope 仅在此 function cellForItemAt indexPath: IndexPath)中,只要控制离开函数的 scope 手势就会识别工作。

You need to hold the strong reference to the tap gesture recognizer, hence I would suggest moving this tap gesture recognizer from your ViewController to GameTileCell instead.您需要保持对点击手势识别器的强引用,因此我建议将此点击手势识别器从您的 ViewController 移动到GameTileCell

So change your GameTiteCell implementation to something like因此,将您的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)
    }
}

Declare a protocol to communicate between your cell and your ViewController.声明一个协议以在您的单元格和您的 ViewController 之间进行通信。 Lets call it as让我们称之为

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

Finally, make your ViewController the delegate of your GameTileCell in cellForRowAtIndexPath最后,让您的 ViewController 成为cellForRowAtIndexPathGameTileCell的代表

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
}

Finally make your ViewController confirm to GameTitleCellProtocol protocol最后让你的 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
            }
        }
    }
}

If you want to add tap and swipe functionality to your cells, you need to define for each a separate gesturerecognizer:如果要向单元格添加点击和滑动功能,则需要为每个单元格定义一个单独的手势识别器:

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

As to why your selector action is not being called: Have you set a breakpoint on this line?至于为什么没有调用您的选择器操作:您是否在此行设置了断点?

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

I think the if might not turn out positive and thus leave your action without doing anything.我认为 if 可能不会变成积极的,因此你什么都不做就离开你的行动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM