Mr_Vlasov
Mr_Vlasov

Reputation: 537

Fail to redraw UICollectionViewCell after reloadData()

I have a UICollectionViewCell:

enter image description here

"Gradient View" is a UIView that has a gradient:

enter image description here

Source of data is CoreData. On Collection view, I have buttons that sort CoreData:

@IBAction func allMealsBtn(_ sender: Any) {
    let fetchRequest: NSFetchRequest<Meal> = Meal.fetchRequest()
    let dateSort = NSSortDescriptor(key: "created", ascending: false)
    fetchRequest.sortDescriptors = [dateSort]

    let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)

    controller.delegate = self
    self.controller = controller

    do {
        try controller.performFetch()
    } catch {
        let error = error as NSError
        print("Couldn't fetch data from CoreData with error: \(error.debugDescription)")
    }
    collectionView.reloadData()

}

After pressing the sort button, collection view reloads and displays the right data. However, the Gradient View multiplies, as though the cell wasn't destroyed. Here what I see after sorting data multiple times:

enter image description here

How to make sure that my cell is redrawn from scratch?

Edit:

My custom cell class. So in configureCell I have to check if my gradientView is added to the view, if yes, then add gradient, if not, add it, and add gradient. How can I do this check?

class CollectionCell: UICollectionViewCell {

@IBOutlet weak var mealImg: UIImageView!
@IBOutlet weak var mealTitleLbl: UILabel!
@IBOutlet weak var gradientView: UIView!

func configureCell(meal: Meal) {
    mealTitleLbl.text = meal.title

    let img = meal.getMealImage()
    mealImg.image = img

    gradientView.addGradientWithColor(color: UIColor.clear)

    // How can I check if my gradientView is added to the view, if yes, then add gradient, if not, add it, and only then add gradient.

}

override func prepareForReuse() {
    super.prepareForReuse()

    gradientView.removeFromSuperview()
}
}

extension UIView {
func addGradientWithColor(color: UIColor) {
    let gradient = CAGradientLayer()
    gradient.frame = self.bounds
    let topColor = UIColor(red:0.07, green:0.07, blue:0.07, alpha:1)
    gradient.colors = [topColor.cgColor, color.cgColor]

    self.layer.insertSublayer(gradient, at: 0)
}
}

Edit: I've dropped the extension and implemented the flag logic. However, after the view gets removed, it never reappears on the cell after performing the search. Any thoughts?

class CollectionCell: UICollectionViewCell {

@IBOutlet weak var mealImg: UIImageView!
@IBOutlet weak var mealTitleLbl: UILabel!
@IBOutlet weak var gradientView: UIView!

var isGradientAdded = false

func configureCell(meal: Meal) {
    mealTitleLbl.text = meal.title

    let img = meal.getMealImage()
    mealImg.image = img

    if isGradientAdded == false {
        addGradient()
        isGradientAdded = true
    }
}

override func prepareForReuse() {
    super.prepareForReuse()

    gradientView.removeFromSuperview()
}

  func addGradient () {
    let gradient = CAGradientLayer()
    gradient.frame = gradientView.bounds
    let topColor = UIColor(red:0.07, green:0.07, blue:0.07, alpha:1)
    let botomColor = UIColor.clear
    gradient.colors = [topColor.cgColor, botomColor.cgColor]
    gradientView.layer.insertSublayer(gradient, at: 0)
}
}

Upvotes: 0

Views: 686

Answers (1)

Evgeny Karkan
Evgeny Karkan

Reputation: 9612

In UICollectionViewCell subclass (Cell) you should override prepeareForReuse function - to turn cell to default mode.

If you don't have the custom class for Cell - create it before and assign in interface builder as class for your Cell cell (and of course don't forget about outlets)

override func prepareForReuse() {
    super.prepareForReuse()

    //set cell to initial state here 
    //e.g try to remove you gradient view  
    yourGradientView.removeFromSuperview()
}

Upvotes: 2

Related Questions