尝试在collectionview中为不可见单元格设置动画时如何防止延迟

Posted

技术标签:

【中文标题】尝试在collectionview中为不可见单元格设置动画时如何防止延迟【英文标题】:how to prevent delay when trying to animate invisible cells in collectionview 【发布时间】:2020-12-30 21:55:36 【问题描述】:

我想为我的所有 collectionview 单元格设置动画,这个简化的示例说明了这个问题。问题是,如果我在动画单元格时向下滚动,那么不可见的单元格会延迟动画。我希望不可见的单元格处于动画的最终状态,而不是动画延迟。

在视频中你看到,当我滚动到底部时,最后的单元格开始延迟动画。

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 
    
    var collectionview: UICollectionView!
    var moveText: Bool = false

    override func viewDidLoad() 
        super.viewDidLoad()
        
        collectionview = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
        collectionview.translatesAutoresizingMaskIntoConstraints = false
        collectionview.dataSource = self
        collectionview.delegate = self
        collectionview.backgroundColor = .systemBackground
        collectionview.register(MyCell.self, forCellWithReuseIdentifier: "cell")
        view.addSubview(collectionview)
        
        NSLayoutConstraint.activate([
            collectionview.topAnchor.constraint(equalTo: view.topAnchor),
            collectionview.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            collectionview.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionview.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        10
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
        UIView.animate(withDuration: 1, delay: 0, options: [
            UIView.AnimationOptions.allowAnimatedContent,
            UIView.AnimationOptions.allowUserInteraction,
        ]) 
            cell.moveText = self.moveText
        
        return cell
    
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
        return .init(width: collectionview.frame.width, height: 120)
    
    
    
    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        
        Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true)  timer in
            print("Starting animatings")
            self.moveText.toggle()
            self.collectionview.reloadData()

        
    
    


class MyCell: UICollectionViewCell 
    
    let label = UILabel()
    var moveText: Bool = false 
        didSet 
            if moveText == true 
                label.transform = CGAffineTransform(translationX: 50, y: 50)
             else 
                label.transform = .identity
            
        
    
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        label.text = "mytext"
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: leadingAnchor),
            label.topAnchor.constraint(equalTo: topAnchor)
        ])
        backgroundColor = .orange
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

【问题讨论】:

【参考方案1】:

而不是在cellForItemAt 中添加这个辅助函数。

private func animateVisibleCells() 
    collectionview.visibleCells.compactMap  $0 as? MyCell .forEach  cell in
        UIView.animate(withDuration: 1, delay: 0, options: [
            UIView.AnimationOptions.allowAnimatedContent,
            UIView.AnimationOptions.allowUserInteraction,
        ]) 
            cell.moveText = self.moveText
        
    

现在调用它而不是重新加载集合视图

Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true)  timer in
    print("Starting animatings")
    self.moveText.toggle()
    self.animateVisibleCells()

并将cellForItemAt 实现转换为:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
    cell.moveText = moveText
    return cell

【讨论】:

感谢您的回答。我明白了,但由于某种原因它不起作用,如果你在动画不可见单元格处于旧位置时快速滚动

以上是关于尝试在collectionview中为不可见单元格设置动画时如何防止延迟的主要内容,如果未能解决你的问题,请参考以下文章

`UICollectionViewLayout` 如何访问不可见单元格的数据?

获取不可见的 CollectionView 单元格

访问 collectionView 单元格可见/不可见

仅更改一个 collectionview 单元格的对象

单元格部分可见的 UICollectionView

无法从 UITest 中的 CollectionView 元素访问单元格