Why doesn't the gradient span the entire width of the view

I'm trying to apply a gradient to a view that is constrained at the top, left, and right of the main screen, but for some reason the gradient doesn't span the entire width of the view in question (see yellow in the picture).

class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let gradient = CAGradientLayer()
        gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
        gradient.startPoint = CGPoint(x:00, y:00)
        gradient.endPoint = CGPoint(x:0, y:0.6)
        gradient.frame = myView.bounds
        myView.clipsToBounds = true
        myView.layer.insertSublayer(gradient, at: 0)
    }
}

      

What am I doing wrong?

enter image description here

+4


source to share


3 answers


Probably the problem is adding the gradient layer in viewDidLoad()

. The view doesn't get its final size until it is viewDidLoad()

.

The view controller can be configured on your XIB / Storyboard for a different screen size than you are using it. (Let's say you have an iPhone SE size, but you're using it at 6. Screen 6 is slightly wider, so the layer will be set to the width of the iPhone SE when the view is first loaded. Then the size will be resized, but the layer will never be resized. )

You have to implement the UIViewController method viewDidLayoutSubviews()

and in this method adjust the border of the layer:

override func viewDidLayoutSubviews() {
  gradientLayer.frame = self.view.bounds
}

      



Thus, if the view is changed (due to automatic rotation, for example), the gradient layer will automatically adjust accordingly.

EDIT:

As pointed out by Sulthan, changes to the layer frame are animated by default. You should probably move the frame change to CATransaction.begin

/ CATransaction.end

and disable actions like below:

override func viewDidLayoutSubviews() {
  CATransaction.begin()
  CATransaction.setDisableActions(true)
  gradientLayer.frame = self.view.bounds
  CATransaction.commit()
}

      

+18


source


You don't need to set a start and end point, given that your goal is for the gradient to span the entire view. You already install this with

gradientLayer.frame = self.view.bounds

      



`

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    var gradientLayer: CAGradientLayer!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        createGradientLayer()
    }

    func createGradientLayer() {
        gradientLayer = CAGradientLayer()

        gradientLayer.frame = self.view.bounds

        gradientLayer.colors = [UIColor.blueColor().CGColor, UIColor.whiteColor().CGColor]

        self.view.layer.addSublayer(gradientLayer)
    }
}

      

+1


source


You can simplify this with CustomClass with one line of code

class GradientView: UIView {
   override class var layerClass: Swift.AnyClass {
      return CAGradientLayer.self
   }
}


// MARK: Usage

let myView: GradientView
guard let gradientLayer = myView.layer as? CAGradientLayer else { return }
gradient.colors = [UIColor.blue.cgColor, UIColor.white.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
gradient.endPoint = CGPoint(x:0, y:0.6)

      

0


source







All Articles