Search code examples
iosswiftcalayerboundscagradientlayer

CAGradientLayer not applying to the full view in programmatically created UI


I'm working on an iOS project that's creating all its UIs programmatically. Not storyboards.

I want to add a gradient to the background of a UIViewController's UIView.

I created the following extension method.

extension UIView {
    
    func addGradient(colors: [UIColor]) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.bounds = bounds
        gradientLayer.colors = colors.map { $0.cgColor }
        layer.insertSublayer(gradientLayer, at: 0)
    }
    
}

And I added the gradient in the viewDidLoad of the ViewController like so.

let topColor = UIColor(red: 0.28, green: 0.521, blue: 0.696, alpha: 1)
let bottomColor = UIColor(red: 0.575, green: 0.615, blue: 0.692, alpha: 1)
view.addGradient(colors: [topColor, bottomColor])

But the gradient is not being applied to the full width and height of the screen.

enter image description here

I printed out the bounds of the view and it shows these values.

(0.0, 0.0, 375.0, 812.0)

So I'm not sure why the gradient is still not covering the full view.


Solution

  • In addGradient(colors:) method set the gradientLayer's frame instead of bounds, i.e.

    func addGradient(colors: [UIColor]) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds //here.....
    
        //rest of the code...
    }
    

    Also, as suggested move your code to viewDidLayoutSubviews() method,

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let topColor = UIColor(red: 0.28, green: 0.521, blue: 0.696, alpha: 1)
        let bottomColor = UIColor(red: 0.575, green: 0.615, blue: 0.692, alpha: 1)
        view.addGradient(colors: [topColor, bottomColor])
    }
    

    This is because, the gradient's frame must change everytime there are any changes in the view's layout. Example, in portrait and landscape orientations.