删除项目后为 CollectionViewCell 设置动画

Posted

技术标签:

【中文标题】删除项目后为 CollectionViewCell 设置动画【英文标题】:Animate CollectionViewCell after deleting item 【发布时间】:2020-03-31 13:22:18 【问题描述】:

对于我的CollectionView,我在willDisplay 中有这个animation

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) 

        // Add animations here
        let animation = AnimationFactory.makeMoveUpWithFade(rowHeight: cell.frame.height, duration: 0.5, delayFactor: 0.1)
        let animator = Animator(animation: animation)
        animator.animate(cell: cell, at: indexPath, in: collectionView)


This 是动画的工作方式(我为CollectionView 实现了它)如果您需要它以获取更多信息。

问题:

在我的项目中,用户可以createdeleteitem

现在collectionViewdeleting 之后没有动画,即使我正在调用reloadData

extension MainViewController: DismissWishlistDelegate 

func dismissWishlistVC(dataArray: [Wishlist], dropDownArray: [DropDownOption]) 
    self.dataSourceArray = dataArray
    self.dropOptions = dropDownArray
    self.makeWishView.dropDownButton.dropView.tableView.reloadData()

    // reload the collection view
    theCollectionView.reloadData()
    theCollectionView.performBatchUpdates(nil, completion: nil)



这是我在另一个ViewController 中调用delegate 的地方:

func deleteTapped()

    let alertcontroller = UIAlertController(title: "Wishlist löschen", message: "Sicher, dass du diese Wishlist löschen möchtest?", preferredStyle: .alert)

    let deleteAction = UIAlertAction(title: "Löschen", style: .default)  (alert) in

        DataHandler.deleteWishlist(self.wishList.index)

        self.dataSourceArray.remove(at: self.currentWishListIDX)
        self.dropOptions.remove(at: self.currentWishListIDX)

        // change heroID so wishlist image doesnt animate
        self.wishlistImage.heroID = "delete"

        self.dismiss(animated: true, completion: nil)

        //  update datasource array in MainVC
        self.dismissWishlistDelegate?.dismissWishlistVC(dataArray: self.dataSourceArray, dropDownArray: self.dropOptions)

    

    let cancelAction = UIAlertAction(title: "Abbrechen", style: .default)  (alert) in
        print("abbrechen")
    


    alertcontroller.addAction(cancelAction)
    alertcontroller.addAction(deleteAction)

    self.present(alertcontroller, animated: true)

creating 动画效果很好。这就是我的createDelegateFunction 的样子:

func createListTappedDelegate(listImage: UIImage, listImageIndex: Int, listName: String) 
    // append created list to data source array
    var textColor = UIColor.white
    if Constants.Wishlist.darkTextColorIndexes.contains(listImageIndex) 
        textColor = UIColor.darkGray
    

    let newIndex = self.dataSourceArray.last!.index + 1

    self.dataSourceArray.append(Wishlist(name: listName, image: listImage, wishData: [Wish](), color: Constants.Wishlist.customColors[listImageIndex], textColor: textColor, index: newIndex))

    // append created list to drop down options
    self.dropOptions.append(DropDownOption(name: listName, image: listImage))

    // reload the collection view
    theCollectionView.reloadData()
    theCollectionView.performBatchUpdates(nil, completion: 
        (result) in
        // scroll to make newly added row visible (if needed)
        let i = self.theCollectionView.numberOfItems(inSection: 0) - 1
        let idx = IndexPath(item: i, section: 0)
        self.theCollectionView.scrollToItem(at: idx, at: .bottom, animated: true)

    )

【问题讨论】:

【参考方案1】:

使用finalLayoutAttributesForDisappearingItem(at:) 和initialLayoutAttributesForAppearingItem(at:) 正确完成IUCollectionView 元素插入和删除的动画

Apple 在finalLayoutAttributesForDisappearingItem(at:) 上的文档摘录

此方法在prepare(forCollectionViewUpdates:) 方法之后和finalizeCollectionViewUpdates() 方法之前调用,用于任何即将被删除的项目。您的实现应该返回描述项目最终位置和状态的布局信息。集合视图使用此信息作为任何动画的终点。 (动画的起点是项目的当前位置。)如果返回 nil,则布局对象对动画的起点和终点使用相同的属性。

【讨论】:

@Chris,Objc.io 博客上提供了很好的解释(文章示例在 Objective C 中,但此后 api 没有太大变化):objc.io/issues/12-animations/collectionview-animations @Chris,CollectionView 在很大程度上取决于布局。在不更改布局的情况下执行影响布局的动画可能容易出错,并可能导致视觉错误。这是我的观点。如果你愿意,你可以使用你的方法,ofc。 感谢您的回答和解释!但现在我想我会坚持我的方式,从来没有任何问题。您对如何解决实际问题有想法吗? 我想要的是一些我可以从reloadscollectionViewanimation的任何地方调用的函数【参考方案2】:

我通过删除performBatchUpdates 解决了这个问题...我不知道它为什么现在起作用以及performBatchUpdates 到底做了什么,但它起作用了,所以如果有人想向我解释它,请随意:D

最终的函数如下所示:

func dismissWishlistVC(dataArray: [Wishlist], dropDownArray: [DropDownOption], shouldDeleteWithAnimation: Bool, indexToDelete: Int) 

    if shouldDeleteWithAnimation 

        self.shouldAnimateCells = true
        self.dataSourceArray.remove(at: self.currentWishListIDX)
        self.dropOptions.remove(at: self.currentWishListIDX)

        // reload the collection view
        theCollectionView.reloadData()


     else 

        self.shouldAnimateCells = false
        self.dataSourceArray = dataArray
        self.dropOptions = dropDownArray

        // reload the collection view
        theCollectionView.reloadData()
        theCollectionView.performBatchUpdates(nil, completion: nil)
    

    self.makeWishView.dropDownButton.dropView.tableView.reloadData()


【讨论】:

以上是关于删除项目后为 CollectionViewCell 设置动画的主要内容,如果未能解决你的问题,请参考以下文章

在点击手势上重置 CollectionviewCell 位置

为啥不去 CollectionViewCell?

CollectionViewCell、MapView 和自定义注解

CollectionViewCell对齐XCode 7.2

创建酷炫的 CollectionViewCell 转换动画

创建酷炫的 CollectionViewCell 转换动画