Kira Arik Kira Arik - 1 year ago 134
Swift Question

Angled Gradient Layer In Swift 2

I have custom

class that renders a gradient. I'm struggling with making an angled gradient so that it draws from the top-left to the bottom-right. Can somebody help me a bit?

import UIKit

class GradientView: UIView {

let gradientLayer = CAGradientLayer()

override func awakeFromNib() {
// 1
self.backgroundColor = ColorPalette.White

// 2
gradientLayer.frame = self.bounds

// 3
let color1 = ColorPalette.GrdTop.CGColor as CGColorRef
let color2 = ColorPalette.GrdBottom.CGColor as CGColorRef
gradientLayer.colors = [color1, color2]

// 4
gradientLayer.locations = [0.0, 1.0]

// 5


I suspect this should be something else but whatever I input nothing changes.

gradientLayer.locations = [0.0, 1.0]

Rob Rob

You don't want to use locations to specify the direction of the gradient. Instead use startPoint and endPoint for that.

The locations array is used when one wants to specify where, in between startPoint and endPoint, the gradient should to take place. For example, if you want the colors to only take place in the middle 10% of the range from the start and end points, you'd use:

locations = [0.45, 0.55]

The locations array doesn't dictate the direction. The startPoint and endPoint do. So, for a diagonal gradient from upper left to lower right, you would set startPoint of CGPoint(x: 0, y: 0) and an endPoint to CGPoint(x: 1, y: 1).

For example:

class GradientView: UIView {

    private let gradientLayer = CAGradientLayer()

    @IBInspectable var color1: UIColor = UIColor.whiteColor() { didSet { updateColors() } }
    @IBInspectable var color2: UIColor = UIColor.blueColor()  { didSet { updateColors() } }

    override init(frame: CGRect) {
        super.init(frame: frame)

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

    func configureGradient() {
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)

    override func layoutSubviews() {

        gradientLayer.frame = bounds

    private func updateColors() {
        gradientLayer.colors = [color1.CGColor, color2.CGColor]

Note, unrelated to the immediate issue:

  • I update the frame of the gradientLayer in layoutSubviews so that as the view's bounds changes, so does the frame of the gradientLayer.
  • Likewise, I set color1 and color2 such that they'll trigger an updating of the gradient, so that any changes in colors will be immediately reflected in the view.
  • I made this @IBDesignable, so that if I drop this in its own framework, and then add the GradientView in IB, I'll see the effect rendered in IB.