3.
Getting Started with View Animations
Written by Marin Todorov
In the previous chapters you got a taste of what creating animations with SwiftUI feels like but now it’s time to go a level deeper into the system and get your hands dirty with some UIKit code.
In this chapter and accompanying project, you’ll learn how to do the following:
- Set the stage for a cool animation.
- Create move and fade animations.
- Adjust the animation easing.
- Reverse and repeat animations.
There’s a fair bit of material to get through, but I promise it will be a lot of fun. Are you up for the challenge?
Your first UIKit animation
Open the starter project located in the Resources folder for this chapter. Build and run your project in Xcode; you’ll see the login screen of a fictional airline app like so:
The app doesn’t do much right now; it just shows a login form with a title, two text fields, and a big friendly button at the bottom.
There’s also a nice background picture and four clouds. The clouds are already connected to outlet variables in the code named cloud1
through cloud4
.
Open ViewController.swift and have a look inside. At the top of the file you’ll see all the connected outlets and class variables. Further down, there’s a bit of code in viewDidLoad()
which initializes some of the UI. The project is ready for you to jump in and shake things up a bit!
Enough with the introductions — you’re undoubtedly ready to try out some code!
Your first task is to animate the form elements onto the screen when the user opens the application. Since the form is now visible when the app starts, you’ll have to move it off of the screen just before your view controller makes an appearance.
Add the following code to viewWillAppear()
:
heading.center.x -= view.bounds.width
username.center.x -= view.bounds.width
password.center.x -= view.bounds.width
This places each of the form elements outside the visible bounds of the screen, like so:
Since the code above executes before the view controller appears, it will look like those text fields were never there in the first place.
Build and run your project to make sure your fields truly appear offscreen just as you had planned:
Perfect — now you can animate those form elements back to their original locations via a delightful animation.
Add the following code to the end of viewDidAppear()
:
UIView.animate(withDuration: 0.5) {
self.heading.center.x += self.view.bounds.width
}
To animate the title into view you call the UIView
class method animate(withDuration:animations:)
. The animation starts immediately and animates over half a second; you set the duration via the first method parameter in the code.
It’s as easy as that; all the changes you make to the view in the animations closure will be animated by UIKit.
Build and run your project; you should see the title slide neatly into place like so:
That sets the stage for you to animate in the rest of the form elements.
Since animate(withDuration:animations:)
is a class method, you aren’t limited to animating just one specific view; in fact you can animate as many views as you want in your animations closure.
Add the following line to the animations closure:
self.username.center.x += self.view.bounds.width
Build and run your project again; watch as the username field slides into place:
Seeing both views animate together is quite cool, but you probably noticed that animating the two views over the same distance and with the same duration looks a bit stiff. Only kill-bots move with such absolute synchronization!
Wouldn’t it be cool if each of the elements moved independently of the others, possibly with a little bit of delay in between the animations?
First remove the line you just added that animates username
:
self.username.center.x += self.view.bounds.width
Then add the following code to the bottom of viewDidAppear()
:
UIView.animate(withDuration: 0.5, delay: 0.3, options: [],
animations: {
self.username.center.x += self.view.bounds.width
},
completion: nil
)
The class method you use this time looks familiar, but it has a few more parameters to let you customize your animation:
-
withDuration
: The duration of the animation. -
delay
: The amount of seconds UIKit will wait before it starts the animation. -
options
: Lets you customize a number of aspects about your animation. You’ll learn more about this parameter later on, but for now you can pass an empty array[]
to mean “no special options”. -
animations
: The closure expression to provide your animations. -
completion
: A code closure to execute when the animation completes. This parameter often comes in handy when you want to perform some final cleanup tasks or chain animations one after the other.
In the code you added above you set delay
to 0.3 to make the animation start just a hair later than the title animation.
Build and run your project; how does the combined animation look now?
Ah — that looks much better. Now all you need to do is animate in the password field.
Add the following code to the bottom of viewDidAppear()
:
UIView.animate(withDuration: 0.5, delay: 0.4, options: [],
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Here you’ve mostly mimicked the animation of the username field, just with a slightly longer delay.
Build and run your project again to see the complete animation sequence:
That’s all you need to do to animate views across the screen with a UIKit animation!
That’s just the start of it — you’ll be learning a few more awesome animation techniques in the remainder of this chapter!
Animatable properties
Now that you’ve seen how easy animations can be, you’re probably keen to learn how else you can animate your views.
This section will give you an overview of the animatable properties of a UIView
, and then guide you through exploring these animations in your project.
Not all view properties can be animated, but all view animations, from the simplest to the most complex, can be built by animating the subset of properties on a view that do lend themselves to animation, as outlined in the next section.
Position and size
You can animate a view’s position and frame in order to make it grow, shrink, or move around as you did in the previous section. Here are the properties you can use to modify a view’s position and size:
-
bounds: Animate this property to reposition the view’s content within the view’s frame.
-
frame: Animate this property to move and/or scale the view.
-
center: Animate this property when you want to move the view to a new location on screen.
Don’t forget that in Swift, several UIKit properties such as size
and center
are mutable . This means you can move a view vertically by changing center.y
or you can shrink a view by decreasing frame.size.width
.
Appearance
You can change the appearance of the view’s content by either tinting its background or making the view fully or semi-transparent.
-
backgroundColor: Change this property of a view to have UIKit gradually change the background color over time.
-
alpha: Change this property to create fade-in and fade-out effects.
Transformation
Transforms modify views in much the same way as above, since you can also adjust size and position.
- transform: Modify this property within an animation block to animate the rotation, scale, and/or position of a view.
These are affine transformations under the hood, which are much more powerful and allow you to describe the scale factor or rotation angle rather than needing to provide a specific bounds or center point.
These look like pretty basic building blocks, but you’ll be surprised at the complex animation effects you’re about to encounter!
Animation options
Looking back to your animation code, you were always passing []
in to the options parameter. options
lets you customize how UIKit creates your animation. You’ve only adjusted the duration and delay of your animations, but you can have a lot more control over your animation parameters than just that.
Below is a list of options declared in the UIView.AnimationOptions
set type that you can combine in different ways for use in your animations.
Repeating
You’ll first take a look at the following two animation options:
-
.repeat
: Include this option to makes your animation loop forever. -
.autoreverse
: Include this option only in conjunction with.repeat
; this option repeatedly plays your animation forward, then in reverse.
Modify the code that animates the password field viewDidAppear()
to use the .repeat
option as follows:
UIView.animate(withDuration: 0.5, delay: 0.4,
options: .repeat,
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Build and run your project to see the effect of your change:
The form title and username field fly in and settle down in the center of the screen, but the password field keeps animating forever from its position offscreen.
Modify the same code you changed above to use both .repeat
and .autoreverse
in the options
parameter as follows:
UIView.animate(withDuration: 0.5, delay: 0.4,
options: [.repeat, .autoreverse],
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Note how if you want to enable more than one option you need to use the set syntax and list all options separated with a comma and enclose the list in square brackets.
Note: If you only need a single option, Swift allows you to omit the square brackets as a convenience. However, you can still include them in case you add more options in the future. That means
[]
for no options,[.repeat]
for a single option, and[.repeat, .autorepeat]
for multiple options.
Build and run your project again; this time the password field just can’t make up its mind about staying on the screen!
Animation easing
In real life things don’t just suddenly start or stop moving. Physical objects like cars or trains slowly accelerate until they reach their target speed, and unless they hit a brick wall, they gradually slow down until they come to a complete stop at their final destination.
The image below illustrates this concept in detail:
To make your animations look more realistic, you can apply the same effect of building momentum at the beginning and slowing down before the end, known in general terms as ease-in and ease-out.
You can choose from four different easing options:
-
.curveLinear
: This option applies no acceleration or deceleration to the animation. The only time in this book you’ll use this option is in the final challenge of Chapter 5: “Transitions”. -
.curveEaseIn
: This option applies acceleration to the start of your animation. -
.curveEaseOut
: This option applies deceleration to the end of your animation. -
.curveEaseInOut
: This option applies acceleration to the start of your animation and applies deceleration to the end of your animation.
To better understand how these options add visual impact to your animation, you’ll try a few of the options in your project.
Modify the animation code for your password field once again with a new option as follows:
UIView.animate(withDuration: 0.5, delay: 0.4,
options: [.repeat, .autoreverse, .curveEaseOut],
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Build and run your project; notice how smoothly the field decelerates until it reaches its rightmost position, before returning to the left side of the screen:
This looks much more natural since that’s how you expect things to move in the real world.
Now, try the opposite. Ease-in the animation when the field is still outside of the screen by modifying the same code as above to change the .curveEaseOut
option to .curveEaseIn
as follows:
UIView.animate(withDuration: 0.5, delay: 0.4,
options: [.repeat, .autoreverse, .curveEaseIn],
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Build and run your project; observe how the field jumps back from its rightmost position with robotic vigor. This looks unnatural and isn’t as visually pleasing as the previous animation.
Finally give .curveEaseInOut
a try. It combines the two options you already know into one very natural looking easing. .curveEaseInOut
is also the default easing function UIKit applies to your animations.
You’ve seen how the various animation options affect your project and how to make movements look smooth and natural.
Before you move on, change the options on the piece of code you’ve been playing with back to []
:
UIView.animate(withDuration: 0.5, delay: 0.4, options: [],
animations: {
self.password.center.x += self.view.bounds.width
},
completion: nil
)
Now that you know how basic animations work, you’re ready to tackle some more dazzling animation techniques.
Key Points
- You create an animation by using one of the variations of
UIView.animate(...)
. - Within the
animations
closure you set the final state of the desired animation and UIKit will automatically create a smooth animation between the current and final states. - You customize your animations by providing
UIView.AnimationOptions
values to set easing, repeating, and autoreversing properties.
Challenges
If this chapter is the first time you’ve animated a view in iOS, your head might be spinning a little. Don’t worry, though, because no matter your initial skillset, you’ll be well on your way to animation mastery in just a few chapters. For now though, there’s one very simple challenge waiting for you where you’ll create an animation of your very own.
Challenge 1: Fade in the clouds
In ViewController you have four outlets: cloud1
, cloud2
, cloud3
, and cloud4
. Your task is to fade those in when the application starts.
You can pretty much decide on the exact form your solution will take, but here’s a list of the basic steps you’ll need to follow:
-
Set the
alpha
property to0.0
for all four cloud views inviewWillAppear()
. -
In
viewDidAppear()
, make four separate calls toanimate(withDuration:delay:options:animations:completion:)
. You’ll get a nice-looking effect if you use a duration of0.5
for all four animations and delays of0.5
,0.7
,0.9
, and1.1
respectively. -
In each
animations
closure change thealpha
of the respective cloud view to1.0
. This will fade the cloud in.
When you run the project you should see a nice transition effect that animates the clouds, one after another:
All views on the screen should animate nicely. Well almost…the Log In button isn’t animating! Don’t worry — you’ll fix that in the next chapter.