11

I have an issue where the data presented in a UICollectionView overwrites the label and the cell view is not getting cleared.

This image shows the issue,

IE:

UICollectionViewCell data is not getting cleared

My UICollectionViewCell which is constructed like so;

// in viewDidLoad
self.playerHUDCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier:reuseIdentifer)

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifer, for: indexPath) as UICollectionViewCell
    let arr = UINib(nibName: "EYPlayerHUDView", bundle: nil).instantiate(withOwner: nil, options: nil)
    let view = arr[0] as! EYPlayerHUDView
    cell.contentView.addSubview(view)
    if let allPlayers = self.allPlayers
    {
        let player:EYPlayer = allPlayers[indexPath.row]
        view.updatePlayerHUD(player: player)
    }
    cell.layoutIfNeeded()
    return cell
}

I use a view to display in the cell.

I tried removing all the cell's subchildren in the cellForItemAt but it appears to remove all the subviews.

I would like to know how do I clear the UICollectionViewCell so labels and other info on the UICollectionViewCell is not dirty like the example above.

Many thanks

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
zardon
  • 1,601
  • 4
  • 23
  • 46
  • Answer is here : http://stackoverflow.com/questions/33940252/duplicate-data-is-loading-when-i-scroll-the-uicollectionview/33940874#33940874 – Mahendra Apr 04 '17 at 08:12
  • Your answer helped. Although the code was in Objective C; I was able to amend and update it for my requirements! – zardon Apr 04 '17 at 08:17
  • override [prepareForResure](https://developer.apple.com/reference/uikit/uicollectionreusableview/1620141-prepareforreuse) method in your custom cell class and add the desired clean up. – Ahmad F Apr 04 '17 at 08:22
  • But there isn't a custom cell class. Consider; the collection view cell is empty and doesn't do anything except add a subview. – zardon Apr 04 '17 at 08:26

4 Answers4

16

Use prepareForReuse method in your custom cell class, something like this:

override func prepareForReuse() {
    super.prepareForReuse()
    //hide or reset anything you want hereafter, for example
    label.isHidden = true
}

in your cellForItemAtIndexPath, instantiate your custom cell:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCellIdentifier", for: indexPath) as! CustomViewCell

Then, always in cellForItemAtIndexPath, setup your items visibility/values

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
carmine
  • 1,597
  • 2
  • 24
  • 33
  • In what file do I put the prepareForReuse? If I put it in my UICollectionViewController it will complain that the function does not override any method in superclass. There is no CustomViewCell; its just a standard UICollectionViewCell – zardon Apr 04 '17 at 08:25
  • You should create a CustomCell e.g: class MyCustomCell: UICollectionViewCell. This is a best approach when you create cells for both CollectionViews and TableViews. Of course it depends on how much you want to customize your cell. See this [tutorial](https://www.raywenderlich.com/136159/uicollectionview-tutorial-getting-started) – carmine Apr 04 '17 at 08:29
  • 1
    It works. Many thanks. Accepted your answer. I removed the subviews I required in the prepareForReuse function – zardon Apr 04 '17 at 08:37
  • Perfect! Glad it helped you! – carmine Apr 04 '17 at 08:40
4
//cell = UICollectionViewCell
for subview in cell.contentView.subviews {
     // you can place "if" condition to remove image view, labels, etc.
     //it will remove subviews of cell's content view
     subview.removeFromSuperview()
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Mahendra
  • 8,448
  • 3
  • 33
  • 56
1

UICollectionViewCells are reused to avoid instantiations, to optimize the performance. If you are scrolling and a cell becomes invisible, the same object is used again (dequeueReusableCell) and a new content is set in cellForItemAt...

As mentioned in the previous answers, before reusing the cell, prepareForReuse() is called on the cell. So you can overrride prepareForReuse() and do whatever preparation you need to do.

You are however creating and adding a new EYPlayerHUDView to the cell on every reuse, so your cell becomes full of stacked EYPlayerHUDViews.

To avoid this, subclass UICollectionViewCell and make the EYPlayerHUDView a property of your custom cell (I recommend to use a XIB):

class MyCell: UICollectionViewCell {
    @IBOutlet var player:EYPlayerHUDView!

    override func prepareForReuse() {
        super.prepareForReuse()
        // stop your player here
        // set your label text = ""
    }
}

After doing so, you can update the EYPlayerHUDView in cellForItemAt without instantiating it and without adding it as new view:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifer, for: indexPath) as? MyCell else {
        return nil
    }

    if let allPlayers = self.allPlayers {
        let player:EYPlayer = allPlayers[indexPath.row]
        cell.player.updatePlayerHUD(player: player)
    }

    return cell
}

(Code untested)

shallowThought
  • 19,212
  • 9
  • 65
  • 112
0

Make custom UICollectionView class and implement prepareForReuse to clear the content if needed.

sanjana
  • 3,034
  • 2
  • 25
  • 31