3

For an iOS app in Swift, I am using programmatic constraints and would like to add a CAGradientLayer() to a UIView(). Below is my code which doesn't work.

   import UIKit

   class ViewController: UIViewController {

       let animationView: UIView = {
           let view = UIView()
           view.translatesAutoresizingMaskIntoConstraints = false
           return view
       }()

       override func viewDidLoad() {
           super.viewDidLoad()

           view.addSubview(animationView)
           setupAnimationView()
           animationView.addGradientLayer()
       }

       func setupAnimationView() {
           animationView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
           animationView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
           animationView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
           animationView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
       }
   }

   extension UIView {

       func addGradientLayer() {
           let color1 = UIColor(red: 251/255, green: 55/255, blue: 91/255, alpha: 1.0)
           let color2 = UIColor(red: 1.0, green: 70/255, blue: 0, alpha: 1.0)
           let gradientLayer = CAGradientLayer()
           gradientLayer.name = "gradientLayer"
           gradientLayer.frame = self.frame
           gradientLayer.colors = [color1.cgColor, color2.cgColor]
           self.layer.insertSublayer(gradientLayer, at: 0)
       }
   }

The issue I am having I believe is related to the fact that I create animationView with programmatic constraints and I then try and add the gradient layer by setting its frame equal to the view of the frame. This code works when I don't use programmatic constraints. Any ideas what I am missing / doing wrong?

Edward
  • 2,864
  • 2
  • 29
  • 39

3 Answers3

8

Any layers that you add to the view will not be managed under AutoLayout and there isn't a way to make this happen.

What you can do is store the layer as a property (perhaps on the view controller).

Then in the method...

override func viewDidLayoutSubviews() {
    super.viewDIdLayoutSubviews()
    // update the layers frame based on the frame of the view.
}

In this method the view will have it's proper frame so if it has changed you will need to update the layer to have a new frame accordingly.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
2

You should change the following line of code:

gradientLayer.frame = self.frame

to:

gradientLayer.frame = bounds

This is important because the frame and the bounds are not using the same coordinate space. Frame is the coordinate space of the superview while bounds is the internal coordinate space of the view.

You can also tell precisely what are the start point and end point of your gradient before adding your gradientLayer to your layer:

gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
layer.addSublayer(gradientLayer)
Ocunidee
  • 1,769
  • 18
  • 20
1

layoutIfNeeded() should be called to updated views immediately.

animationView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
animationView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
animationView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
animationView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

view.layoutIfNeeded()
Matt
  • 1,711
  • 18
  • 20