Gradients

Episode #284 | 11 minutes | published on July 14, 2017 | Uses swift-3.0, Xcode-8.3
Gradients are slowly returning to be part of the common iOS design aesthetic once again (after iOS 7 introduced an entirely flat design paradigm). Subtle gradients can be used to create interesting designs, provide necessary contrast for drawing text on top of photos, and provide a realistic feel to custom controls. Learn how to create linear and radial gradients, how to define custom locations to control the position and "shape" of the gradient.

Links

Creating a CGGradient

Gradients are created with colorspaces, colors, and locations.

If you specify a color space and any of the colors are in a different color space, then the system will convert them. It is
recommended to just pass colors in a consistent color space to avoid any conversion.

let colors = [
    CGColor(colorSpace: colorSpace, components: [0.2, 0.2, 0.8, 1])!,
    CGColor(colorSpace: colorSpace, components: [0.6, 0.4, 1, 1])!
] as CFArray

let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil)!

Creating a Linear Gradient

A linear gradient will travel along a straight line, filling the perpendicular axis with color defined by the gradient. This is often a vertical line, but doesn't have to be if you want the gradient to travel diagonally.

context.drawLinearGradient(gradient, start: CGPoint(x: 30, y: 30), end: CGPoint(x: 290, y: 290), options: [])

Here the gradient starts at 30, 30 and ends at 290, 290. By default the gradient won't draw outside the start & end points, so you'll have a clipped drawing. If you want the edges to extend and fill the entire container, then you can specify some options:

context.drawLinearGradient(gradient, start: CGPoint(x: 30, y: 30), end: CGPoint(x: 290, y: 290), options: [
    .drawsBeforeStartLocation,
    .drawsAfterEndLocation
])

The gradient will just continue repeating the color defined at the start and end of the gradient.

Creating a Radial Gradient

To draw a radial gradient, you'll need at least one point to use as the center:

let center = CGPoint(x: rect.midX, y: rect.midY)

Then we can define a startRadius which will control how big our "circle" will be. To expand to the edges of our rect:

let startRadius = rect.width / 2

We can ignore the endCenter and endRadius for now.

context.drawRadialGradient(gradient, startCenter: center, startRadius: rect.width, endCenter: center, endRadius: 0, options: [])

This will draw a circle with our gradient expanding inward. If we use a non-zero value for endRadius then we'll end up with a donut, which might be appropriate for some sort of radial control, but often not really useful. Using a different center value will create a sort of tunnel effect.

To have the gradient fill our entire rect, we can either expand the startRadius to rect.width to ensure that the circle will encompass the entire thing (clipping a significant portion of it) or use the .drawsBeforeStartLocation option.

blog comments powered by Disqus