Core Graphics Tutorial: Patterns and Playgrounds
Learn how to draw a repeatable pattern and use Playgrounds to prototype drawing a complex image. By Andrew Kharchyshyn.
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: Patterns and Playgrounds
25 mins
- Getting Started
- Repeating Pattern for Background
- Setting up BackgroundView
- Drawing Triangles
- Getting an Image From a Context
- @IBDesignable Attributes
- Drawing Images
- Xcode Playground
- Drawing Theory
- Lower Ribbon
- Clasp
- Medallion
- Upper Ribbon
- Number One
- Creating Shadows
- Adding the Medal Image to an Image View
- MedalView Setup
- Animating
- Where to Go From Here?
In this tutorial, you’ll learn how to draw a repeating pattern on a view’s background, how to use Swift Playgrounds to quickly prototype your Core Graphics drawings, how to get the best out of your drawings, and how to add simple animations.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of this tutorial.
In this tutorial, you’ll work on a water drinking tracking app, called Flo. You might remember this app from Core Graphics Tutorial: Getting Started or Core Graphics Tutorial: Gradients and Contexts tutorials. If you missed them, this is a good time to read them first, but you can also start right here.
You’re going to take Flo to its final form. Specifically, you’ll:
- Create a repeating pattern for the background
- Draw a medal from start to finish to award users for successfully drinking eight glasses of water a day
- Add a simple keypath animation to the button
Repeating Pattern for Background
Your mission in this section is to use the pattern methods in UIKit to create this background pattern:
Setting up BackgroundView
Go to File ▸ New ▸ File…, select the iOS ▸ Source ▸ Cocoa Touch Class template and choose Next. Enter BackgroundView for the Class field and UIView for Subclass of. Make sure Swift is selected for the language. Click Next, and then Create.
Go to Main.storyboard, select the main view of ViewController
and change the class to BackgroundView in the Identity inspector.
Replace the code in BackgroundView.swift with:
import UIKit
@IBDesignable
class BackgroundView: UIView {
// 1
@IBInspectable var lightColor: UIColor = .orange
@IBInspectable var darkColor: UIColor = .yellow
@IBInspectable var patternSize: CGFloat = 200
override func draw(_ rect: CGRect) {
// 2
guard let context = UIGraphicsGetCurrentContext() else {
fatalError("\(#function):\(#line) Failed to get current context.")
}
// 3
context.setFillColor(darkColor.cgColor)
// 4
context.fill(rect)
}
}
Then, open Main.storyboard and notice the background view of your storyboard is yellow now. Here’s why:
-
lightColor
,darkColor
andpatternSize
have@IBInspectable
attributes, so it’s easier to configure their values in the Interface Builder later. You’re using orange and yellow as temporary colors, just so you can see what’s happening.patternSize
controls the size of the repeating pattern. It’s initially set to large, again so it’s easy to see what’s happening. -
UIGraphicsGetCurrentContext()
gives you the view’s context and is also wheredraw(_:)
draws. - Use the Core Graphics
setFillColor()
to set the current fill color of the context. Notice that you need to useCGColor
, a property ofdarkColor
when using Core Graphics. - Instead of setting up a rectangular path,
fill()
takes up the entire context with the current fill color.
Drawing Triangles
You’re now going to draw these three orange triangles using UIBezierPath
. The numbers correspond to the points in the following code:
Still in BackgroundView.swift, add this code to the end of draw(_:)
:
let drawSize = CGSize(width: patternSize, height: patternSize)
// Insert code here
let trianglePath = UIBezierPath()
// 1
trianglePath.move(to: CGPoint(x: drawSize.width / 2, y: 0))
// 2
trianglePath.addLine(to: CGPoint(x: 0, y: drawSize.height / 2))
// 3
trianglePath.addLine(to: CGPoint(x: drawSize.width, y: drawSize.height / 2))
// 4
trianglePath.move(to: CGPoint(x: 0, y: drawSize.height / 2))
// 5
trianglePath.addLine(to: CGPoint(x: drawSize.width / 2, y: drawSize.height))
// 6
trianglePath.addLine(to: CGPoint(x: 0, y: drawSize.height))
// 7
trianglePath.move(to: CGPoint(x: drawSize.width, y: drawSize.height / 2))
// 8
trianglePath.addLine(to: CGPoint(x: drawSize.width / 2, y: drawSize.height))
// 9
trianglePath.addLine(to: CGPoint(x: drawSize.width, y: drawSize.height))
lightColor.setFill()
trianglePath.fill()
Notice how you use one path to draw three triangles. move(to:)
is just like lifting your pen from the paper and moving it to a new spot when you’re drawing.
Open Main.storyboard and you’ll see an orange and yellow image at the top left of your background view.
So far, you’ve drawn directly into the view’s drawing context. To repeat this pattern, you must create an image outside the context and then use that image as a pattern in the context.
Find the following line in BackgroundView.swift. It’s close to the top of draw(_:)
, but after the initial context call:
let drawSize = CGSize(width: patternSize, height: patternSize)
Add the following code where it conveniently says // Insert code here
:
UIGraphicsBeginImageContextWithOptions(drawSize, true, 0.0)
guard let drawingContext = UIGraphicsGetCurrentContext() else {
fatalError("\(#function):\(#line) Failed to get current context.")
}
// Set the fill color for the new context
darkColor.setFill()
drawingContext
.fill(CGRect(x: 0, y: 0, width: drawSize.width, height: drawSize.height))
Hey! Those orange triangles disappeared from the storyboard. Where did they go?
UIGraphicsBeginImageContextWithOptions(_:_:_:)
creates a new context and sets it as the current drawing context, so you’re now drawing into this new context. The parameters of this method are:
- The size of the context.
- Whether the context is opaque. If you need transparency, then this needs to be
false
. - The scale of the context. If you’re drawing to a Retina screen on iPhone 11, this should be 2.0, and if to an iPhone 12, it should be 3.0. Here, you use 0.0 instead, which ensures the correct scale for the device is automatically applied.
Then, you used UIGraphicsGetCurrentContext()
to get a reference to this new context.
Next, you filled the new context with yellow. You could have let the original background show through by setting the context opacity to false
, but it’s faster to draw opaque contexts.
Getting an Image From a Context
Add this code to the end of draw(_:)
:
guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
fatalError("""
\(#function):\(#line) Failed to \
get an image from current context.
""")
}
UIGraphicsEndImageContext()
This extracts a UIImage
from the current context. When you end the current context with UIGraphicsEndImageContext()
, the drawing context reverts to the view’s context. So any further drawing in draw(_:)
happens in the view.
To draw the image as a repeated pattern, add this code to the end of draw(_:)
:
UIColor(patternImage: image).setFill()
context.fill(rect)
This creates a new UIColor
by using an image as a color instead of a solid color.
Build and run the app. You should now have a rather bright background for your app.