Episode #392

Custom Gradient Background

Series: Making a Podcast App From Scratch

13 minutes
Published on May 23, 2019

This video is only available to subscribers. Get access to this video and 584 others.

In this episode we create a custom UIView subclass that draws a gradient overlay. This allows us to overlap the podcast information above the artwork slightly.

Custom Gradient Background

In this episode, we create a custom UIView subclass that draws a gradient overlay. This allows us to overlap the podcast information above the artwork slightly.

Create A Custom Gradient Background View

We will start by creating a custom UIView that will draw a gradient background. To have our custom view rendered in Interface Builder, we will mark the class as @IBDesignable and implement prepareForInterfaceBuilder to set it up with any initialization we need.

import UIKit

@IBDesignable
class GradientBackgroundView : UIView {
    override func awakeFromNib() {
        super.awakeFromNib()
        commonSetup()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        commonSetup()
    }

    private func commonSetup() {
        backgroundColor = .clear
        isOpaque = false
    }
}   

We need to make sure that we never crash when drawing, otherwise the @IBDesignable will not render in Interface Builder and it will be difficult to understand why. So here if creating the gradient fails we can simply fill in the view with red so we can see the error right away.

override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let colors = [
        startColor.cgColor,
        endColor.cgColor
    ] as CFArray
    let locations: [CGFloat] = [startLocation, endLocation]
    guard let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: locations) else {
        UIColor.red.setFill()
        context.fill(rect)
        return
    }

    let start = CGPoint.zero
    let end = CGPoint(x: 0, y: rect.height)

    context.drawLinearGradient(gradient, start: start, end: end, options: [
        .drawsBeforeStartLocation,
        .drawsAfterEndLocation
    ])
}

Now we will set a few @IBInspectable properties for color and location, so any change in these properties during design would redraw the view.

@IBInspectable var startColor: UIColor = .clear {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable var endColor: UIColor = Theme.Colors.gray5 {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable var startLocation: CGFloat = 0.0 {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable var endLocation: CGFloat = 0.25 {
    didSet {
        setNeedsDisplay()
    }
}

This episode uses Xcode 10.2.1, Swift 5.0.