UIImageView 动画在 UICollectionViewCell 中不能正常工作

UIImageView animated doesn't work properly inside UICollectionViewCell

我想在 UICollectionViewCell 中添加一个 UIImageView 动画,所以我想出了这个代码:

    import UIKit

class MainViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    var items:[String] = ["one", "two", "three", "four"]

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 1.0)
        self.view.addSubview(self.collectionView)
    }

    lazy var collectionView:UICollectionView = {
        var cv = UICollectionView(frame: self.view.bounds, collectionViewLayout: self.flowLayout)
        cv.delegate = self
        cv.dataSource = self
        cv.bounces = true
        cv.alwaysBounceVertical = true
        cv.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
        cv.registerClass(CustomCell.self, forCellWithReuseIdentifier: "cell")
        cv.backgroundColor = UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 1.0)
        return cv
    }()

    lazy var flowLayout:UICollectionViewFlowLayout = {
        var flow = UICollectionViewFlowLayout()
        flow.sectionInset = UIEdgeInsetsMake(2.0, 2.0, 2.0, 2.0)
        return flow
    }()


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{

        let width:CGFloat = self.view.bounds.size.width*0.98;
        let height:CGFloat = 150.0;
        return CGSizeMake(width, height)
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
        return self.items.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CustomCell
        cell.layer.cornerRadius = 4
        cell.backgroundColor = UIColor.whiteColor()
        cell.imgView.animationImages = ["1","2","3","4","5", "6","7","8"].map{UIImage(named: [=10=])!}
        cell.imgView.animationDuration = NSTimeInterval(0.8)
        cell.imgView.startAnimating()
        return cell
    }

    func collectionView(collectionView: UICollectionView, shouldHighlightItemAtIndexPath indexPath: NSIndexPath) -> Bool {
         return true
    }

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        var alert = UIAlertController(title: "Alert!", message: "Cell tapped", preferredStyle: UIAlertControllerStyle.Alert)
        var action = UIAlertAction(title: "ok", style: UIAlertActionStyle.Cancel) { (dd) -> Void in }
        alert.addAction(action)
        self.presentViewController(alert, animated: true, completion: nil)
    }

}

这是我的 MainViewController,以编程方式添加了 CollectionView

    import UIKit

class CustomCell: UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.addSubview(self.imgView)
    }

    lazy var imgView:UIImageView = {
        var iv = UIImageView()
        iv.contentMode = UIViewContentMode.ScaleAspectFill
        return iv
    }()

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.imgView.frame = CGRectMake(6,15,self.frame.width*0.2, self.frame.height*0.8)
    }
}

这是我的习惯 UICollectionViewCell UIImageView

我的问题是当您点击一个单元格时 UIImageView 消失了。为了解决这个问题,我开始寻找另一种 UICoolectionView delegate 方法。然后我尝试使用 shouldHighlightItemAtIndexPath,但是如果我使用此方法返回 false 动画工作正常但集合视图停止响应 didSelectItemAtIndexPath.

这是一个 github 存储库,其中包含显示问题的代码:https://github.com/gazolla/ImageAnimation更新了解决方案

解决方案:

在 matt 的帮助下,我对代码进行了以下更改:

1) 添加图像数组到 highlightedAnimationImages 属性

let animationArray = ["1","2","3","4","5", "6","7","8"].map{UIImage(named: [=12=])!}
cell.imgView.highlightedAnimationImages = animationArray

2) 取消选择单元格时重新启动动画

 func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
    if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? CustomCell{
        cell.imgView.startAnimating()
    }
 }

3) 选择单元格时重新启动动画

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! CustomCell
    cell.imgView.startAnimating()

    //...

}

解决方案 2:

经过一些测试,我发现当你点击并按住时,一个单元格UIImageView又消失了,所以我们必须用另外两种方法重新启动动画:

1) didHighlightItemAtIndexPath

func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {
        if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? CustomCell{
            cell.imgView.startAnimating()
        }

  }

2) didUnhighlightItemAtIndexPath

func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {
    if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? CustomCell{
        cell.imgView.startAnimating()
    }
}

当您 select 单元格时,图像视图查看它的 highlightedAnimationImages,而不是 animationImages。您没有设置 highlightedAnimationImages,所以您什么也看不到。

这是一个截屏视频,显示它可以工作。当背景为灰色(即它的 selectedBackgroundView)时单元格被 select 编辑,但动画继续:

如果其他人遇到这个讨厌的错误并且上述解决方案没有帮助 - 尝试在您的单元格的 prepareForReuse() 函数中调用 imageView.stopAnimating()

Swift 来自@Sebastian 的解决方案 2 的 4 版本。

func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) as? CustomCell {
        cell.imgView.startAnimating()
    }
}

func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) as? CustomCell {
        cell.imgView.startAnimating()
    }
}

我遇到了同样的问题,但是我没有让 "didDeselectItemAtIndexPath" 工作,所以我解决这个问题的方法只是在图片上添加一个没有功能的按钮。

所以当你触摸图片时,你会触摸到按钮。

给了我灵感。当 UITableViewCell isSelectedisHighlighted 状态改变时,它会调用 setSelected:animated:setHighlighted:animated 方法。所以,我重写了自定义 UITableViewCell 的方法。

class DCFWFailReasonCell: UITableViewCell {

    // Local flag for UIImageView animation.
    fileprivate var isAnimation: Bool = false

    // Setup animation images 
    func configure(animateImage: [UIImage], duration: TimeInterval) {
        imgView.animationImages = animateImage
        imgView.highlightedAnimationImages = animateImage
        
        imgView.animationDuration = duration
        imgView.animationRepeatCount = 0 //< 0 infinite
        
        imgView.startAnimating()

        // imgView has animation.         
        isAnimation = true
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        
        // 
        if (self.isAnimation) {
            imgView.startAnimating()
        }
    }
    
    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
        super.setHighlighted(highlighted, animated: animated)
        
        if (self.isAnimation) {
            imgView.startAnimating()
        }
    }

}

这是我的解决方案,效果很好

class MyImageView: UIImageView {
    
    override func stopAnimating() {
        super.stopAnimating()
        startAnimating()
    }
}