0
votes

TL;DR: Have 2 views (top and bottom) that need CAGradientLayer. Unexpected behavior is that only Top View displays gradient. Bottom doesn't display Gradient.

In our application, I have a view that has a UICollectionView as seen on the image: Whole device

For each UICollectionViewCell, I created a custom class to do the layout details. On the UICollectionViewCell, I have a "topBackground" and "bottomBackground", which are views that will content labels with info for each Cell:

@IBOutlet weak var topBackground: UIView! 
@IBOutlet weak var bottomBackground: UIView!

The Top and Bottom Views, Labels were displaying correctly and the constraints working.

We decided to add a gradient effect on the Top and Bottom View (see details on image, top gradient marked in red and bottom detail marked in yellow) enter image description here.

For the code, we used the following:

override func layoutSubviews() {
        if !didLayout{                
             // Top View
            let gradientLayer: CAGradientLayer = CAGradientLayer()
            gradientLayer.frame = topBackground.frame
            gradientLayer.colors =
                [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0).cgColor]
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.9)
            topBackground.layer.insertSublayer(gradientLayer, at: 0)
            topBackground.backgroundColor = .clear
            topBackground.alpha = 0.5

            // Bottom View
            let gradientLayerBottom: CAGradientLayer = CAGradientLayer()
            gradientLayerBottom.frame = bottomBackground.frame
            gradientLayerBottom.colors =
                [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0).cgColor]
            gradientLayerBottom.startPoint = CGPoint(x: 0.5, y: 0.9)
            gradientLayerBottom.endPoint = CGPoint(x: 0.5, y: 0)
            bottomBackground.layer.insertSublayer(gradientLayerBottom, at: 0)
            bottomBackground.backgroundColor = .clear
            bottomBackground.alpha = 0.5

            didLayout = true
        } else {
            print("already performed layout")
        }
    }

The variable didLayout is to avoid overlapping multiple gradients when scrolling the collection view.

Results:

  1. The Top View is displaying the Gradient (Expected).
  2. Bottom View is not displaying Gradient (Unexpected).

We know the bottom view is there with the constraints working, because if we change the color to other than .clear, it displays the other color. It's just gradientLayerBottom that is not being displayed.

Any ideas on how to get gradientLayerBottom to be displayed?

1
why are you inserting sublayer at 0? - Lu_
@Lu_ Tried to make sure it was the on the first position of layer.sublayers. Also tried addSublayer, instead of insertSublayer(at:) but same results. - Victor Sanchez
and if you set up the same starting and ending points as in top gradient layer? it is weird, code looks ok - Lu_
@Lu_ If I set the same start and end points, same result, the bottom one is not displaying. - Victor Sanchez

1 Answers

1
votes

Try this

extension UIView{
    func setGradientBackgroundImage(colorTop: UIColor, colorBottom: UIColor) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.frame = bounds
        layer.insertSublayer(gradientLayer, at: 0)
    }
}

Put in UICollectionViewCell class

class CollVwCell : UICollectionViewCell{

    @IBOutlet weak var VwTop: UIView!
    @IBOutlet weak var VwBottom: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        DispatchQueue.main.async {
            self.VwTop.setGradientBackgroundImage(colorTop: UIColor.red, colorBottom: UIColor.white)
            self.VwBottom.setGradientBackgroundImage(colorTop: UIColor.white, colorBottom: UIColor.purple)
        }
    }
}

Output:

enter image description here