【问题标题】:Button flickering when reloading data in CollectionVIew在 CollectionVIew 中重新加载数据时按钮闪烁
【发布时间】:2021-06-17 02:09:57
【问题描述】:

我正在通过在集合视图中点击按钮来更新类别图像。我有一个collectionView,当点击按钮并且图像发生变化时,它具有淡入动画。我也尝试使用reloadItem,但它仍然闪烁。

我发现问题是因为我在单元格更新中调用reloadData引起的,但是当按下按钮时我找不到正确的方法。

视图控制器


import UIKit
import CoreData


class WordsVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
  
    
  
    @IBOutlet weak var wordsCategoryCollection: UICollectionView!
    

    override func viewDidLoad() {
        super.viewDidLoad()

        wordsCategoryCollection.delegate = self
        wordsCategoryCollection.dataSource = self
        wordsCategoryCollection.isScrollEnabled = false
        wordsCategoryCollection.backgroundColor = nil
        
        roundCounter = 1
    }

    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return words.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WordsCategoryCell", for: indexPath) as? WordsCategoryCell {
            cell.backgroundColor = UIColor.clear
            
            
            cell.wordsBtn.tag = indexPath.row
            cell.wordsBtn.addTarget(self, action: #selector(changeCategoryStatus), for: .touchUpInside)
            cell.updateCell(word: words[indexPath.row])
            return cell
        }
        return UICollectionViewCell()
    }
    
    @objc func changeCategoryStatus(_ sender: UIButton!) {
        debugPrint(sender.tag)
        if words[sender.tag].categoryIsEnable == true {
                words[sender.tag].categoryIsEnable = false
                words[sender.tag].categoryImageName.removeLast()
                words[sender.tag].categoryImageName.append("F")
              } else {
                words[sender.tag].categoryIsEnable = true
                words[sender.tag].categoryImageName.removeLast()
                words[sender.tag].categoryImageName.append("T")
              }
        
        debugPrint("\(words[0].categoryImageName) - \(words[0].categoryIsEnable)")
        debugPrint("\(words[1].categoryImageName) - \(words[1].categoryIsEnable)")
        debugPrint("\(words[2].categoryImageName) - \(words[2].categoryIsEnable)")
        wordsCategoryCollection.reloadData()
        //wordsCategoryCollection.reloadItems(at: [IndexPath(row: sender.tag, section: 0)])
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        getWordsForTheGame()
    }
    
    @IBAction func playBtn(_ sender: Any) {
        performSegue(withIdentifier: "MainVC", sender: nil)
    }
    
}


单元格

class WordsCategoryCell: UICollectionViewCell {

    @IBOutlet weak var wordsBtn: UIButton!
    
    func updateCell(word: word) {
        let image = UIImage(named: word.categoryImageName)
        wordsBtn.setTitle(nil, for: .normal)
        wordsBtn.setImage(image, for: .normal)
    }
    
}

GIF

【问题讨论】:

    标签: ios swift uicollectionview uibutton reloaddata


    【解决方案1】:

    我建议您不要将reloadData() 用于您想要实现的目标。相反,我会推荐这个:

    func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
            collectionView.indexPathsForSelectedItems?.forEach({ collectionView.deselectItem(at: $0, animated: false) })
            //this function will make it so only one cell can be selected at a time
            //don't add this if you want multiple cells to be selected at the same time.
            return true
        }
        
        func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
            self.checkNumberOfAnswers()
            let cell = collectionView.cellForItem(at: indexPath) as! WordsCategoryCell
            //animate the cell that is getting unselected here
        }
        
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
            self.checkNumberOfAnswers()
            let cell = collectionView.cellForItem(at: indexPath) as! WordsCategoryCell
            //animate the cell that is getting selected here
        }
    

    您可以按照您想要的方式为您选择的单元格设置动画,甚至可以更改其数据,因为您可以访问该单元格,对于未被选中的单元格也是如此。

    只需在您的单元格内覆盖 isSelected 并将其设置为在单元格被选中和未选中时执行您想要的操作。

    public override var isSelected: Bool {
            didSet {
                switch self.isSelected {
                case true:
                    //do stuff when selected
                case false:
                    //do stuff when unselected
                }
            }
        }
    

    编辑:

    reloadData() 使用 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 中的所有代码重新创建当前加载的 所有 单元格(因为您正在出队),对于这个特定用例来说效率不高,因为它运行额外再次代码,如果它已经在视图中并且使用您的配置加载,则无需再次设置每个单元格的背景颜色以清除、设置按钮标签等。您看到的其他细胞发生的小动画可能是细胞在您眼前再次创建的副作用。 与其更改 words 数组中的数据,不如更改已创建的单元格中的数据。

    reloadData() 更好地用于实际重新加载新数据,例如,当您从服务器发出请求并获得一个新数组来更新您的单元格时,您将 didSet 放在该数组上,当 @ 987654328@ 运行它将reloadData,使用实际的新信息/数据重新创建单元格。

    至于如何使用按钮,首先我建议您在单元格中添加 @objc 方法以提高可读性,因为这是您的按钮所在的位置,并使用委托在您的 ViewController 中获得通知。

    其次,您需要 indexPath 来访问单元格,而不是 indexPath.row,因此在您的单元格中创建一个名为 indexPath 的可选变量,类型为 IndexPath,并在创建单元格时将其设置为 indexPath

    cell.indexPath = indexPath
    

    现在,在您的单元格中创建一个委托,该委托具有在您按下按钮时传递 indexPath 的函数,例如:

    protocol categoryCellDelegate {
        func buttonPressed(index: IndexPath)       
    }
    

    通过符合协议以及在 VC 内部调用函数时获取 VC 内部的 indexPath:

    func buttonPressed(index: IndexPath) {
          let cell = wordsCategoryCollection.cellForItem(at: index) as! WordsCategoryCell
        //now do anything your want with this cell like change image, color, etc...
    }
    

    为什么我推荐使用 CollectionView 的 didSelectItemAt 主要是因为它已经为你提供了所有这些以及更多。

    直到一个月前,我一直使用一个按钮(我已经编写 Swift 代码 8 个月了),直到我想创建一个测验系统,一次只能选择给定部分中的一个单元格,确保未选中前一个单元格并选择新单元格所涉及的头痛是不值得的。所以我使用了 Collections View 自己的选择方法,看到它是多么简单,它给了我我想要的一切,并开始更多地使用它。

    【讨论】:

    • 有没有办法用按钮做到这一点?我是 swift 新手,如果您能说出为什么您的解决方案更好,我将不胜感激)
    • 编辑了答案以包含这些,如果您有更多问题或您想要实现的目标,请告诉我。
    猜你喜欢
    • 2016-06-05
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 2023-03-22
    • 2017-07-19
    • 2013-10-08
    相关资源
    最近更新 更多