How to Create a Complex Loading Animation in Swift
Learn how to create a complex loading animation in Swift with this step-by-step tutorial. By Satraj.
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
How to Create a Complex Loading Animation in Swift
20 mins
With more than 1.4 million apps in the iOS App Store today, it’s a real challenge to make your app stand out. You have a very small window of opportunity to capture the attention of your users before your app ends up in the big black hole of obscurity.
There’s no better place to start wowing your users than at the loading screen of your app, where you can add a delightful animation that serves as a precursor to your on-boarding or authentication workflow.
In this tutorial you will learn how to make such an animation. You’ll learn how to build it up piece-by-piece, utilising advanced techniques to create a fluid and captivating animation.
Getting Started
Download the starter project for this tutorial here, save it to a convenient location and open it in Xcode.
Open HolderView.swift. In this UIView
subclass, you will add and animate the following sublayers (found in the Layers subgroup) as shown in the animation above:
- OvalLayer.swift: This is the first layer, which expands from zero size and then wobbles for a short period of time.
-
TriangleLayer.swift: This next layer appears while the
OvalLayer
is wobbling. When this view rotates,OvalLayer
contracts back to zero size leaving just theTriangleLayer
visible. -
RectangleLayer.swift: This layer serves as a visual container of sorts for the
TriangleLayer
. -
ArcLayer.swift: This layer fills the
RectangleLayer
with an animation effect that’s very similar to a glass being filled with water.
Open OvalLayer.swift; the starter project already contains the code to initialize this layer and all the Bezier paths you’ll use in your animations. You’ll see that expand()
, wobble()
and contract()
are all empty; you’ll populate those methods as you work through the tutorial. All the other *Layer files are structured in a similar fashion.
Finally, open ViewController.swift and take a look at addHolderView()
; this method adds an instance of HolderView
as a subview to the center of the view controller’s view. This view will house all the animations. The view controller just needs to put it on the screen, and the view will take care of the actual animation code.
The animateLabel()
function is a delegate callback provided by the HolderView
class that you will fill in as you complete the animation sequence. addButton()
simply adds a button to the view so that you can tap and restart the animation.
Build and run your app; you should see an empty white screen. An empty canvas — the perfect thing on which to start creating your new animations! :]
By the end of this tutorial, your app will look like this:
So without further ado, let’s get started!
Adding The Oval
The animation starts with a red oval that expands into view from the centre of the screen and then wobbles around a bit.
Open HolderView.swift and declare the following constant near the top of the HolderView
class:
let ovalLayer = OvalLayer()
Now add the following function to the bottom of the class:
func addOval() {
layer.addSublayer(ovalLayer)
ovalLayer.expand()
}
This first adds the OvalLayer
instance you created above as a sublayer to the view’s layer, then calls expand()
, which is one of the stubbed-out functions you need to fill in.
Go to OvalLayer.swift and add the following code to expand()
:
func expand() {
var expandAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")
expandAnimation.fromValue = ovalPathSmall.CGPath
expandAnimation.toValue = ovalPathLarge.CGPath
expandAnimation.duration = animationDuration
expandAnimation.fillMode = kCAFillModeForwards
expandAnimation.removedOnCompletion = false
addAnimation(expandAnimation, forKey: nil)
}
This function creates an instance of CABasicAnimation
that changes the oval’s path from ovalPathSmall
to ovalPathLarge
. The starter project provides both of these Bezier paths for you. Setting removedOnCompletion
to false
and fillMode
to KCAFillModeForwards
on the animation lets the oval retain its new path once the animation has finished.
Finally, open ViewController.swift and add the following line to addHolderView()
just below view.addSubview(holderView)
:
holderView.addOval()
This calls addOval
to kickstart the animation after it has been added to the view controller’s view.
Build and run your app; your animation should now look like this:
Wobbling The Oval
With your oval now expanding into view, the next step is to put some bounce in its step and make it wobble.
Open HolderView.swift and add the following function to the bottom of the class:
func wobbleOval() {
ovalLayer.wobble()
}
This calls the stubbed-out method wobble()
in OvalLayer
.
Now open OvalLayer.swift and add the following code to wobble()
:
func wobble() {
// 1
var wobbleAnimation1: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation1.fromValue = ovalPathLarge.CGPath
wobbleAnimation1.toValue = ovalPathSquishVertical.CGPath
wobbleAnimation1.beginTime = 0.0
wobbleAnimation1.duration = animationDuration
// 2
var wobbleAnimation2: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation2.fromValue = ovalPathSquishVertical.CGPath
wobbleAnimation2.toValue = ovalPathSquishHorizontal.CGPath
wobbleAnimation2.beginTime = wobbleAnimation1.beginTime + wobbleAnimation1.duration
wobbleAnimation2.duration = animationDuration
// 3
var wobbleAnimation3: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation3.fromValue = ovalPathSquishHorizontal.CGPath
wobbleAnimation3.toValue = ovalPathSquishVertical.CGPath
wobbleAnimation3.beginTime = wobbleAnimation2.beginTime + wobbleAnimation2.duration
wobbleAnimation3.duration = animationDuration
// 4
var wobbleAnimation4: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation4.fromValue = ovalPathSquishVertical.CGPath
wobbleAnimation4.toValue = ovalPathLarge.CGPath
wobbleAnimation4.beginTime = wobbleAnimation3.beginTime + wobbleAnimation3.duration
wobbleAnimation4.duration = animationDuration
// 5
var wobbleAnimationGroup: CAAnimationGroup = CAAnimationGroup()
wobbleAnimationGroup.animations = [wobbleAnimation1, wobbleAnimation2, wobbleAnimation3,
wobbleAnimation4]
wobbleAnimationGroup.duration = wobbleAnimation4.beginTime + wobbleAnimation4.duration
wobbleAnimationGroup.repeatCount = 2
addAnimation(wobbleAnimationGroup, forKey: nil)
}
That’s a lot of code, but it breaks down nicely. Here’s what’s going on:
- Animate from the large path down to being squished vertically.
- Change from a vertical squish to squished both horizontally and vertically.
- Swap back to vertical squish.
- Finish the animation, ending back at the large path.
- Combine all of your animations into a
CAAnimationGroup
and add this group animation to yourOvalLayout
.
The beginTime
of each subsequent animation is the sum of the beginTime
of the previous animation and its duration
. You repeat the animation group twice to give the wobble a slightly elongated feel.
Even though you now have all the code required to produce the wobble animation, you aren’t calling your new animation yet.
Go back to HolderView.swift and add the following line to the end of addOval()
:
NSTimer.scheduledTimerWithTimeInterval(0.3, target: self, selector: "wobbleOval",
userInfo: nil, repeats: false)
Here you create a timer that calls wobbleOval()
right after the OvalLayer
has finished expanding.
Build and run your app; check out your new animation:
It’s very subtle, but that’s an important factor of a truly delightful animation. You don’t need things to be flying all over the screen!