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
Filling In The Container
With your container now in place, the next phase of the animation is to fill it up. The effect you’re looking for is that of water filling up a glass. This is a great visual effect and sets things up for a big…splash! :]
Open HolderView.swift and add the following constant just below the two RectangleLayer
properties:
let arcLayer = ArcLayer()
Now add the following code to the end of drawBlueAnimatedRectangle()
:
NSTimer.scheduledTimerWithTimeInterval(0.40, target: self, selector: "drawArc",
userInfo: nil, repeats: false)
This creates a timer to call drawArc()
once the blue RectangleLayer
finishes drawing.
Add the following function to the end of the class:
func drawArc() {
layer.addSublayer(arcLayer)
arcLayer.animate()
}
This adds the instance of ArcLayer
created above to the HolderView
‘s layer before you animate in the fill.
Open ArcLayer.swift and add the following code to animate()
:
func animate() {
var arcAnimationPre: CABasicAnimation = CABasicAnimation(keyPath: "path")
arcAnimationPre.fromValue = arcPathPre.CGPath
arcAnimationPre.toValue = arcPathStarting.CGPath
arcAnimationPre.beginTime = 0.0
arcAnimationPre.duration = animationDuration
var arcAnimationLow: CABasicAnimation = CABasicAnimation(keyPath: "path")
arcAnimationLow.fromValue = arcPathStarting.CGPath
arcAnimationLow.toValue = arcPathLow.CGPath
arcAnimationLow.beginTime = arcAnimationPre.beginTime + arcAnimationPre.duration
arcAnimationLow.duration = animationDuration
var arcAnimationMid: CABasicAnimation = CABasicAnimation(keyPath: "path")
arcAnimationMid.fromValue = arcPathLow.CGPath
arcAnimationMid.toValue = arcPathMid.CGPath
arcAnimationMid.beginTime = arcAnimationLow.beginTime + arcAnimationLow.duration
arcAnimationMid.duration = animationDuration
var arcAnimationHigh: CABasicAnimation = CABasicAnimation(keyPath: "path")
arcAnimationHigh.fromValue = arcPathMid.CGPath
arcAnimationHigh.toValue = arcPathHigh.CGPath
arcAnimationHigh.beginTime = arcAnimationMid.beginTime + arcAnimationMid.duration
arcAnimationHigh.duration = animationDuration
var arcAnimationComplete: CABasicAnimation = CABasicAnimation(keyPath: "path")
arcAnimationComplete.fromValue = arcPathHigh.CGPath
arcAnimationComplete.toValue = arcPathComplete.CGPath
arcAnimationComplete.beginTime = arcAnimationHigh.beginTime + arcAnimationHigh.duration
arcAnimationComplete.duration = animationDuration
var arcAnimationGroup: CAAnimationGroup = CAAnimationGroup()
arcAnimationGroup.animations = [arcAnimationPre, arcAnimationLow, arcAnimationMid,
arcAnimationHigh, arcAnimationComplete]
arcAnimationGroup.duration = arcAnimationComplete.beginTime + arcAnimationComplete.duration
arcAnimationGroup.fillMode = kCAFillModeForwards
arcAnimationGroup.removedOnCompletion = false
addAnimation(arcAnimationGroup, forKey: nil)
}
This animation is very similar to the earlier wobble animation; you create a CAAnimationGroup
that contains five instances of a path-based CABasicAnimation
. Each path has a slightly different arc with increasing height and is part of the starter project. Finally, you apply the CAAnimationGroup
to the layer and instruct it to not be removed on completion so it will retain its state when the animation has finished.
Build and run your app to watch the magic unfold!
Completing The Animation
All that’s left to do is expand the blue HolderView
to fill in the entire screen and add a UILabel
to the view to serve as the logo.
Open HolderView.swift and add the following code to the end of drawArc()
:
NSTimer.scheduledTimerWithTimeInterval(0.90, target: self, selector: "expandView",
userInfo: nil, repeats: false)
This creates a timer that calls expandView()
after the ArcLayer
fills up the container.
Now, add the following function to the bottom of the same class:
func expandView() {
// 1
backgroundColor = Colors.blue
// 2
frame = CGRectMake(frame.origin.x - blueRectangleLayer.lineWidth,
frame.origin.y - blueRectangleLayer.lineWidth,
frame.size.width + blueRectangleLayer.lineWidth * 2,
frame.size.height + blueRectangleLayer.lineWidth * 2)
// 3
layer.sublayers = nil
// 4
UIView.animateWithDuration(0.3, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
self.frame = self.parentFrame
}, completion: { finished in
self.addLabel()
})
}
Here’s what that method does:
- The background of the holder view is set to blue, to match the color you filled the rectangle with.
- The frame is expanded to account for the
RectangleLayer
‘s stroke width that you added earlier. - All sublayers are removed. Now there are no oval, no triangle and no rectangle layers.
- An animation is added to expand the
HolderView
to fill the screen. Once that animation’s done, you calladdLabel()
.
Add the following function to the bottom of the class:
func addLabel() {
delegate?.animateLabel()
}
This simply calls the view’s delegate function to animate the label.
Now open ViewController.swift and add the following code to animateLabel()
:
func animateLabel() {
// 1
holderView.removeFromSuperview()
view.backgroundColor = Colors.blue
// 2
var label: UILabel = UILabel(frame: view.frame)
label.textColor = Colors.white
label.font = UIFont(name: "HelveticaNeue-Thin", size: 170.0)
label.textAlignment = NSTextAlignment.Center
label.text = "S"
label.transform = CGAffineTransformScale(label.transform, 0.25, 0.25)
view.addSubview(label)
// 3
UIView.animateWithDuration(0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.1, options: UIViewAnimationOptions.CurveEaseInOut,
animations: ({
label.transform = CGAffineTransformScale(label.transform, 4.0, 4.0)
}), completion: { finished in
self.addButton()
})
}
Taking each commented section in turn:
- Remove
HolderView
from the view and set the view’s background color to blue. - Create a
UILabel
with text of ‘S’ to represent the logo, and add it to the view. - Apply a spring animation to the label to scale it in. Once the animation is done, call
addButton()
to add a button to your view, which, when pressed, repeats the animation.
Build and run the application, give yourself a pat on the back and take a moment to enjoy what you’ve built! :]
Where to Go From Here?
You can download the final completed project here.
This tutorial covered quite a few different animation techniques that, when stacked together, create a rather complex loading animation that really makes your app shine on first run.
From here, feel free to play around with different timings and shapes to see what cool animations you can come up with.
If you want to take your new found animation skills to the next level, then I suggest you check out our book, iOS Animations by Tutorials.
I hope that you had a ton of fun going through this tutorial, and if you have any questions or comments, please join the forum discussion below!