7
votes

I want to put a gradient background in all my views.

The way that I thought to do this without the need to create a IBOutlet of a view in all view controllers is to create a new class from UIView, and inside the draw() I put the code that makes a CAGradientLayer in the view.

So, in the interface builder I just need to select the background view and set its class as my custom class. It works so far.

My question is if I can do that without problems. Somebody knows is it ok? Because the model file that inherit from UIView come with the comment: //Only override draw() if you perform custom drawing.

And I don't know if create a layer counts. Or if draw() is only to low level drawing or something like that. Do not know nothing about the best usage of the draw() func.

This is the code:

override func draw(_ rect: CGRect) {

        let layer = CAGradientLayer()
        layer.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)

        let color1 = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
        let color2 = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)

        layer.colors = [color1.cgColor, color2.cgColor]
        self.layer.addSublayer(layer)
    }
3
You need the location property for your gradient layer.El Tomato

3 Answers

12
votes

You can use @IBDesignable and @IBInspectable to configure the startColor and endColor properties from the Storyboard. Use CGGradient which specifies colors and locations instead of CAGradientLayer if you want to draw in draw(_ rect:) method. The Simple Gradient class and draw(_ rect: CGRect) function would look like this

import UIKit

@IBDesignable 
class GradientView: UIView {

    @IBInspectable var startColor: UIColor = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
    @IBInspectable var endColor: UIColor = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)

    override func draw(_ rect: CGRect) {

      let context = UIGraphicsGetCurrentContext()!
      let colors = [startColor.cgColor, endColor.cgColor]

      let colorSpace = CGColorSpaceCreateDeviceRGB()

      let colorLocations: [CGFloat] = [0.0, 1.0]

      let gradient = CGGradient(colorsSpace: colorSpace,
                                     colors: colors as CFArray,
                                  locations: colorLocations)!

      let startPoint = CGPoint.zero
      let endPoint = CGPoint(x: 0, y: bounds.height)
      context.drawLinearGradient(gradient,
                          start: startPoint,
                            end: endPoint,
                        options: [CGGradientDrawingOptions(rawValue: 0)])
    }
}

you can read more about it here and tutorial

1
votes

You shouldn't be adding a CAGradientLayer inside the draw function.

If you want to add a gradient to a view then the easiest way is to do it with a layer (like you are doing) but not like this...

You should add it to your view as part of the init method and then update its frame in the layout subviews method.

Something like this...

class MyView: UIView {
    let gradientLayer: CAGradientLayer = {
        let l = CAGradientLayer()
        let color1 = UIColor(red: 4/255, green: 39/255, blue: 105/255, alpha: 1)
        let color2 = UIColor(red: 1/255, green: 91/255, blue: 168/255, alpha: 1)
        l.colors = [color1.cgColor, color2.cgColor]
        return l
    }()

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

        layer.addSublayer(gradientLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        gradientLayer.frame = bounds
    }
}
1
votes

I would create UIView extension and apply it when needed.

extension UIView {
        func withGradienBackground(color1: UIColor, color2: UIColor, color3: UIColor, color4: UIColor) {
            let layerGradient = CAGradientLayer()

            layerGradient.colors = [color1.cgColor, color2.cgColor, color3.cgColor, color4.cgColor]
            layerGradient.frame = bounds
            layerGradient.startPoint = CGPoint(x: 1.5, y: 1.5)
            layerGradient.endPoint = CGPoint(x: 0.0, y: 0.0)
            layerGradient.locations = [0.0, 0.3, 0.4, 1.0]

            layer.insertSublayer(layerGradient, at: 0)
        }
}

Here you can change func declaration to specify startPoint, endPointand locations params as variables.

After that just call this method like

gradienView.withGradienBackground(color1: UIColor.green, color2: UIColor.red, color3: UIColor.blue, color4: UIColor.white)

P.S. Please note that you can have as much colors as you want in colors array