Core Graphics Tutorial: Gradients and Contexts
In this Core Graphics tutorial, learn how to develop a modern iOS app with advanced Core Graphics features like gradients and transformations. By Fabrizio Brancati.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Core Graphics Tutorial: Gradients and Contexts
30 mins
- Core Graphics
- Getting Started
- Creating the Graph
- Setting Up the Animated Transition
- Analyzing the Graph View
- Drawing a Gradient
- Clipping Areas
- Calculating Graph Points
- Creating the Gradient for the Graph
- Drawing the Data Points
- Considering Context States
- Adding the Graph Labels
- Mastering the Matrix
- Drawing the Marker
- Where to Go to From Here?
Welcome back to our modern Core Graphics tutorial series!
In Core Graphics Tutorial: Getting Started, you learned about drawing lines and arcs with Core Graphics and using Xcode’s interactive storyboard features.
In this second part, you’ll delve further into Core Graphics, learning about drawing gradients and manipulating CGContexts
with transformations.
Core Graphics
You’re now going to leave the comfortable world of UIKit and enter the underworld of Core Graphics.
This image from Apple describes the relevant frameworks conceptually:
UIKit is the top layer, and it’s also the most approachable. You’ve used UIBezierPath
, which is a UIKit wrapper of the Core Graphics CGPath
.
The Core Graphics framework is based on the Quartz advanced drawing engine. It provides low-level, lightweight 2D rendering. You can use this framework to handle path-based drawing, transformations, color management and much more.
One thing to know about lower layer Core Graphics objects and functions is that they always have the prefix CG
, so they are easy to recognize.
Getting Started
By the time you get to the end of this tutorial, you’ll have created a graph view that looks like this:
Before drawing on the graph view, you’ll set it up in the storyboard and create the code that animates the transition to show it.
The complete view hierarchy will look like this:
First, download the project materials by clicking the Download Materials button at the top or bottom of this tutorial. When you open it, you’ll see that it’s pretty much where you left off in the previous tutorial. The only difference is that in Main.storyboard, CounterView
is inside of another view with a yellow background. Build and run, and this is what you’ll see:
Creating the Graph
Go to File ▸ New ▸ File…, choose the iOS ▸ Source ▸ Cocoa Touch Class template and click Next. Enter the name GraphView as the class name, choose the subclass UIView and set the language to Swift. Click Next then Create.
Now in Main.storyboard click the name of the yellow view in the Document Outline and press Enter to rename it. Call it Container View. Drag a new UIView
from the object library inside of Container View, below the Counter View.
Change the class of the new view to GraphView in the Identity inspector. The only thing left is to add constraints for the new GraphView
, similar to how you added constraints in the previous part of the tutorial:
- With the GraphView selected, Control-drag from the center slightly left, still within the view, and choose Width from the pop-up menu.
- With the GraphView still selected, Control-drag from the center slightly up, still within the view, and choose Height from the pop-up menu.
- Control-drag left from inside the view to outside the view and choose Center Horizontally in Container.
- Control-drag up from inside the view to outside the view, and choose Center Vertically in Container.
Edit the constraint constants in the Size inspector to match these:
Your Document Outline should look like this:
The reason you need a Container View is to make an animated transition between the Counter View and the Graph View.
Go to ViewController.swift and add property outlets for the Container and Graph views:
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var graphView: GraphView!
This creates an outlet for the Container and Graph views. Now hook them up to the views you created in the storyboard.
Go back to Main.storyboard and hook up the Graph View and the Container View to their corresponding outlets:
Setting Up the Animated Transition
While still in Main.storyboard, drag a Tap Gesture Recognizer from the Object Library to the Container View in the Document Outline:
Next, go to ViewController.swift and add this property to the top of the class:
var isGraphViewShowing = false
This simply marks whether the Graph View is currently displayed.
Now add this tap method to do the transition:
@IBAction func counterViewTap(_ gesture: UITapGestureRecognizer?) {
// Hide Graph
if isGraphViewShowing {
UIView.transition(
from: graphView,
to: counterView,
duration: 1.0,
options: [.transitionFlipFromLeft, .showHideTransitionViews],
completion: nil
)
} else {
// Show Graph
UIView.transition(
from: counterView,
to: graphView,
duration: 1.0,
options: [.transitionFlipFromRight, .showHideTransitionViews],
completion: nil
)
}
isGraphViewShowing.toggle()
}
UIView.transition(from:to:duration:options:completion:)
performs a horizontal flip transition. Other available transitions are cross dissolve, vertical flip and curl up or down. The transition uses .showHideTransitionViews
so that you don’t have to remove the view to prevent it from being shown once it is “hidden” in the transition.
Add this code at the end of pushButtonPressed(_:)
:
if isGraphViewShowing {
counterViewTap(nil)
}
If the user presses the plus button while the graph is showing, the display will swing back to show the counter.
Now, to get this transition working, go back to Main.storyboard and hook up your tap gesture to the newly added counterViewTap(gesture:)
:
Build and run. Currently, you’ll see the Graph View when you start the app. Later on, you’ll set the Graph View hidden, so the counter view will appear first. Tap it and you’ll see the flip transition.
Analyzing the Graph View
Remember the Painter’s Model from Part 1? It explained that you draw an image from back to front in Core Graphics. So you need the order in mind before you code. For Flo’s graph, that would be:
- Gradient background view
- Clipped gradient under the graph
- Graph line
- Circles for the graph points
- Horizontal graph lines
- Graph labels
Drawing a Gradient
You’ll now draw a gradient in the Graph View.
Open GraphView.swift and replace the code with:
import UIKit
@IBDesignable
class GraphView: UIView {
// 1
@IBInspectable var startColor: UIColor = .red
@IBInspectable var endColor: UIColor = .green
override func draw(_ rect: CGRect) {
// 2
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let colors = [startColor.cgColor, endColor.cgColor]
// 3
let colorSpace = CGColorSpaceCreateDeviceRGB()
// 4
let colorLocations: [CGFloat] = [0.0, 1.0]
// 5
guard let gradient = CGGradient(
colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations
) else {
return
}
// 6
let startPoint = CGPoint.zero
let endPoint = CGPoint(x: 0, y: bounds.height)
context.drawLinearGradient(
gradient,
start: startPoint,
end: endPoint,
options: []
)
}
}
Here’s what you need to know from the code above:
- You need to set the start and end colors for the gradient as
@IBInspectable
properties so that you’ll be able to change them in the storyboard. - CG drawing functions need to know the context in which they will draw, so you use the UIKit method
UIGraphicsGetCurrentContext()
to obtain the current context. That’s the one thatdraw(_:)
draws into. - All contexts have a color space. This could be CMYK or grayscale, but here you’re using the RGB color space.
- The color stops describe where the colors in the gradient change over. In this example, you only have two colors, red going to green, but you could have an array of three stops, and have red going to blue going to green. The stops are between 0 and 1, where 0.33 is a third of the way through the gradient.
- You then need to create the actual gradient, defining the color space, colors and color stops.
- Finally, you need to draw the gradient.
drawLinearGradient(_:start:end:options:)
takes the following parameters:- The
CGGradient
with color space, colors and stops - The start point
- The end point
- Option flags to extend the gradient
- The
The gradient will fill the entire rect
passed to draw(_:)
.
Open Main.storyboard and you’ll see the gradient appear on the Graph View.
In the storyboard, select the Graph View. Then in the Attributes inspector, change Start Color to RGB(250, 233, 222), and End Color to RGB(252, 79, 8). To do this, click the color, then Custom:
Now for some clean up work. In Main.storyboard, select each view in turn, except for the main view, and set the Background Color to Clear Color. You don’t need the yellow color any more and the push button views should have a transparent background anyway.
Build and run, and you’ll notice the graph looks a lot nicer, or at least its background does. :]