Silver Challenge

Interesting. I guess I misunderstood the ordering of the lifecycle methods then. Do you happen to know a place where I can reference this information? I found the following image on apple’s dev site but this is just the lifecycle of the view controller at a high level and doesn’t seem to go into the details of the layout lifecycle

Thanks so much! I wasn’t seeing anything and guessed my layer had no width or height but I couldn’t figure out how to give it a size. The gradientLayer.frame.size = view.frame.size fixed me up.
Really great. thanks for the help

1 Like

Full solution:


(In order to understand don’t just copy & paste, write the code yourself and run each time before you go to the next line to see the difference.)

import UIKit

class ViewController: UIViewController {
    let gradientLayer = CAGradientLayer()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        // Silver Challange - Chapter 3 - page 161
        
        gradientLayer.colors = [ UIColor.purple.cgColor, UIColor.blue.cgColor, UIColor.green.cgColor,
                                 UIColor.yellow.cgColor, UIColor.orange.cgColor, UIColor.red.cgColor]
        gradientLayer.frame = view.bounds
        
        view.layer.insertSublayer(gradientLayer, at: 0)
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        gradientLayer.frame = view.bounds
    }
}

Common mistakes:

  • Just creating a layer and add it as sublayer won’t make any changes in UI. but it doesn’t mean it is not there. It just doesn’t have a size so it won’t be displayed. Therefore we give it a size as equal to its hosting view object(UIViewController) to fill the entire screen by doing : gradientLayer.frame = view.bounds

  • Adding layer as sublayer using view.layer.addSublayer(gradientLayer) will do the trick. But there is a problem: your sublayer will be rendered over all labels so we won’t see any of the labels:
    The correct way to add it is: view.layer.insertSublayer(gradientLayer, at: 0). Second argument: at: 0 means insert this layer at index 0 before anything else (labels in our case).

  • When rotating the orientation you will notice a bug: half of the screen is displaying layer and half is not.
    To fix this we override viewWillLayoutSubviews() and include gradientLayer.frame = view.bounds. We do this because when changing orientation the ViewController’s view has a new size(landscape) now but our layer still has the old size(portrait).

2 Likes

Adding subLayer puts it at the very top (above the other layers). Instead you want to insert subLayer at 0 (view.layer.insertSublayer(gradientLayer, at: 0)) to put it behind the rest of the content (all the text you have there).

When you put a bp to pause right before adding the subLayer, you can see that the other subLayers are what the text sits on. See screenshot. This is an easier way to see how adding the gradient on top would block all the rest. That’s why we want to insert the subLayer at position 0, so that everything else stays on top.

By the way, you can play around with it by inserting sublayer at various positions to see how it will block certain text and not others.