0

I have a UICollectionViewCell with a gradient subview. In my view controller, I have buttons that are sorting CoreData and then reloadData() on the UICollectionView. To avoid my gradient subview to be drawn again and again (as it happened in the past), I implement removeFromSuperview() in prepareForReuse(). There I also implement a flag that keeps track of gradient existence so I still add a new gradient when cell is load. However after removing the gradient, my willMove(toSuperview: ) doesn't work, and gradient view doesn't appear. What's wrong with my logic?

class CollectionCell: UICollectionViewCell {

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

var gradientWasRemoved = false

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

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

    addGradient()    
}

  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)

    if gradientWasRemoved == true {
        gradientView.willMove(toSuperview: self)
    } 
}

override func prepareForReuse() {
    super.prepareForReuse()

   gradientView.removeFromSuperview()
   gradientWasRemoved = true
}
}
Mr_Vlasov
  • 515
  • 2
  • 6
  • 25
  • http://stackoverflow.com/questions/24380535/how-to-apply-gradient-to-background-view-of-ios-swift-app/37243106#37243106 – Leo Dabus Jan 31 '17 at 02:07
  • 1
    In my opinion, your `gradientView` is `weak` and it will be nil after you called `gradientView.removeFromSuperview()`. – nynohu Jan 31 '17 at 02:08
  • Are you saying that the gradient view isn't added back? Maybe you need to be sure to call addSubview on the cell since I can't see you adding that back in. – Luis Jan 31 '17 at 02:09
  • @LeoDabus with this code, a view with a gradient won't be copied again and again ? – Mr_Vlasov Jan 31 '17 at 02:11
  • @Luis When I added 'self.addSubview(gradientView)' in 'gradientWasRemoved' condition check, my gradient was added but again, with a double gradient on it. – Mr_Vlasov Jan 31 '17 at 02:16
  • @Mr_Vlasov put a break point on the addGradient method and figure where you may be calling it twice from. Also why remove the view in the first place? You could just nil it out in prepareForReuse and recreate it in addGradient since you seem to be calling that every init. – Luis Jan 31 '17 at 02:18
  • @LeoDabus "copied" as in the new cell, the new gradient covers the old one. My code logic keeps creating that gradient View and adding it in .insertSublayer( )' in 'addGradient' func. I implement the conditional flag check (gradientWasRemoved) but the gradient still doesn't appear. – Mr_Vlasov Jan 31 '17 at 02:21
  • @Mr_Vlasov UICollectionViewCell inherits from UIView. Just do the same I did to UIView. Change the declaration from `class GradientView: UIView {` to `class GradientViewCell: UICollectionViewCell {` – Leo Dabus Jan 31 '17 at 02:40
  • In your CollectionViewController method cellForItemAt indexPath: `let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellID", for: indexPath) as! GradientViewCell` – Leo Dabus Jan 31 '17 at 02:41
  • don't forget to select the cell in your storyboard change it to `GradientViewCell ` and add the reuse ID "CollectionCellID" – Leo Dabus Jan 31 '17 at 02:42

1 Answers1

0

I was able to fix the logic with following. In UICollectionViewCell class:

import UIKit

class CollectionCell: UICollectionViewCell {

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

@IBOutlet weak var mealTitleLbl: UILabel!

var gradientWasRemoved = false

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

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

    addGradient()
}

  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]

    if gradientWasRemoved == false {
    gradientView.layer.insertSublayer(gradient, at: 0)
    } else if gradientWasRemoved == true {
        self.addSubview(gradientView)
    }
}

override func prepareForReuse() {
    super.prepareForReuse()

   gradientView.removeFromSuperview()
   gradientWasRemoved = true
}

}

In prepareForReuse( ) I didn't delete gradientView, I removed it from the Superview. I set the flag there that it was removed. Since I didn't nil my gradientView i was able to run addGradient() and access gradientView.bounds for creation of new CGGradientLayer. Right before adding a new layer to gradientView, I performed if check. If we did remove gradientView then we don't add a new CGGradientLayer but simply put our gradientView back. This way we add CGGradientLayer to our gradientView only once.

I learned that by removing views from Superview they are still alive and can be edited.

Thank you @Luis and @LeoDabus for your contribution.

Mr_Vlasov
  • 515
  • 2
  • 6
  • 25