Silver Challenge

Added the following to viewController:

override func viewDidLoad()
{
    super.viewDidLoad()

    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [UIColor.red.cgColor,
                            UIColor.green.cgColor,
                            UIColor.blue.cgColor]
    gradientLayer.frame.size = view.frame.size
    
    view.layer.insertSublayer(gradientLayer, at:0)
}

I’m not sure what the hint was talking about wrt modifying viewWillLayoutSubview, I didn’t find it necessary to override that function to get the gradient to display correctly. Maybe that’s necessary if you add the gradient layer through Interface Builder rather than programmatically, but I couldn’t find a way to do it through IB.

1 Like

I came up with almost the exact same solution, the only difference being the way of setting the gradient layer’s frame which on my code looks as follows:

myLayer.frame = view.bounds

I was also wondering about the exact same thing regarding the viewWillLayoutSubviews(), perhaps it’s a matter of style and correctness and that’s the place where changes like these should be made? But as you said, it wasn’t necessary.

The documentation offers hints as to when viewWillLayoutSubviews might come in handy. The key is the change in bounds.

// Declaration:
viewWillLayoutSubviews()

Called to notify the view controller that its view is about to layout its subviews.

// Discussion
When a view’s bounds change, the view adjusts
the position of its subviews.

Your view controller can override this method
to make changes before the view lays out its subviews.

The default implementation of this method does nothing.

1 Like

At first I didn’t think I’d ever need to update the gradient subview since it filled the whole screen & that would never resize.

Then I tried rotating the phone. Oh, that’s when.

So now the view controller looks like this:

class ViewController: UIViewController {

    var gradientLayer: CAGradientLayer = CAGradientLayer()

    override func viewDidLoad()
    {
        super.viewDidLoad()

        gradientLayer.colors = [UIColor.red.cgColor,
                                UIColor.green.cgColor,
                                UIColor.blue.cgColor]
        gradientLayer.frame.size = view.frame.size
    
        view.layer.insertSublayer(gradientLayer, at:0)
    }

    override func viewWillLayoutSubviews()
    {
        super.viewWillLayoutSubviews()
    
        gradientLayer.frame.size = view.frame.size
    }
}

This mostly works, except for upside down. :thinking:

Edit: Apparently there’s a project setting you need to change to get that orientation to work. It’s in the General settings, under Deployment Info. There are 4 check boxes for each of the 4 screen orientations. Upside Down is the only one not checked by default. Check that & rebuild, and then upside down works.

They should have made this the gold challenge, it wound up being more involved than implementing equal spacing.

1 Like

I’m new to iOS Development. I was having trouble with the Silver challenge, I read through the chapter again and I also attempted to read the documentation, but I didn’t understand how to provide the solution? The documentation is really confusing also, can anyone please offer any insight into how they came up with the solution and offer any guidance to help me understand as well? Thanks in advance.

First, they explicitly tell you you’re going to add a CAGradientLayer to the view. Looking back at the section earlier in the chapter where we added rectangles to the view, I knew I would be doing that in viewDidLoad. Looking at the documentation for CAGradientLayer told me how to set up the colors for the gradient. Poking around a bit in the documentation for CALayer I figured out how to set the frame size.

Figuring out how to add the layer behind the other components took a few tries, but I eventually figured that out from looking at the documentation for UIView.

For the last bit I needed a bit of help here which you can read above.

Thank you! I will re-read and try to come up with the solution again.

How come addSublayer does not work here? Any ideas?

If I’m remembering correctly, addSubLayer put the gradient on top of everything else instead of behind. That’s because addSubLayer adds the new layer to the end of the sublayers array, and the items in the sublayers array are drawn in order - sublayers[0] is drawn first, then sublayers[1] is drawn on top of that, and so on. If the gradient is at the end of the array it is drawn last, blocking out everything that was drawn before it, so you have to make sure it gets drawn first by inserting it at the beginning of the array. And because we’re adding the gradient in viewDidload, the other items on the screen are already in the array.

1 Like

I make code like this.

class ViewController: UIViewController {

     let gradientLayer = CAGradientLayer()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        gradientLayer.frame = view.bounds
        gradientLayer.colors = [ UIColor.purple.cgColor, UIColor.blue.cgColor, UIColor.green.cgColor, 
  UIColor.yellow.cgColor, UIColor.orange.cgColor, UIColor.red.cgColor]

        // Rasterize this static layer to improve app performance.
        gradientLayer.shouldRasterize = true
        view.layer.addSublayer(gradientLayer)
       

    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
    }
}

Simulator shows below. Label is hidden.

Thanks for the thorough explanation!