Getting Started with SwiftUI Animations
In this tutorial, you’ll learn how to add fancy animations with SwiftUI. You’ll go from basic animations to complex and custom spring animations. By Michael Katz.
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
Getting Started with SwiftUI Animations
30 mins
- Getting Started
- Preview Window
- Basic Animations
- Animation Timing
- Tinkering With Timing
- Simultaneous Animations
- Animating State Changes
- Transitions
- Combining Transitions
- Asynchronous Transitions
- Springs
- Using SwiftUI’s Pre-Built Spring Options
- Refining the Animation
- Animatable
- An Alternate Look at Animatable Data
- Other Ways to Animate
- Where to Go From Here?
SwiftUI brings a ton of new features and an easier way of writing UI code to all of Apple’s platforms. As an added bonus, it also has a new way of animating state transitions.
If you’re used to UIView
animations, you may find these easier to write and understand. If you’re jumping in with SwiftUI, congratulations! This will let you “easeIn” to it. That’s an animation joke! :]
In this tutorial, you’ll learn the basics of SwiftUI animation, including:
- The
animation
modifier. -
withAnimation
, the function which lets you animate state changes. - Custom animations.
It’s best to use Xcode 11.2.1 or later, which contains fixes for known animation bugs in the SwiftUI code. You’ll have an easier time if you’re running macOS Catalina, because Xcode will show the code and live preview side-by-side in the Canvas pane.
However, if you still have Mojave, that’s fine too; you can just build and run to see how code changes affect the app. In fact, this technique is still handy on Catalina, as the preview window can be buggy.
This tutorial assumes a working knowledge of SwiftUI. You should be comfortable with components such as Text
, Image
, HStack
and VStack
. If you’re just getting started with SwiftUI, check out this tutorial first.
Getting Started
Use the Download Materials button at the top or bottom of this tutorial to download the projects for this tutorial.
The tutorial app, MySolarSystem, is a simple inventory of the planets in your solar system (assuming you’re reading this on Earth). Once completed, tapping a row will show each planet with a list of that planet’s largest moons. From there, tapping a moon will provide additional information about the planet to the user.
ContentView
represents the main screen of the app. It is a List
that makes a table from the array of Planet
s. Each element in the list is an HStack
with several controls: an Image
for the planet’s picture, a Text
for the planet’s name, a Spacer
and finally a Button
, if the planet has any moons. The purpose of this button is to show information about the moons.
Later in this tutorial, you’ll put the optional MoonList
in the VStack
. Tapping the moon button will show or hide it. This will be the first thing you’ll add and animate.
Preview Window
If you’re running on macOS Catalina, you have access to the Canvas in the editor pane. If you don’t see it, enable it by selecting Editor ▸ Canvas. This will show the view and live update as you change the code.
If you click the Live Preview button, aka the play icon, it will make the preview interactive. Once you add animations and interactivity, you’ll be able to click buttons and observe state changes.
Automatic preview updating paused
. If you see that, just click Resume to rebuild the preview. Also, if an animation doesn’t appear to be working, double check by running the app in the simulator or on a device. The live app is the source of truth for any UI behaviors.Basic Animations
To add animations, the first thing you need is something to animate. So to start, you’ll create a state change that triggers an update to the UI.
Open ContentView.swift and add the following to the end of the VStack
in makePlanetRow(planet:)
:
if self.toggleMoons(planet.name) {
MoonList(planet: planet)
}
This checks toggleMoons(_:)
to determine if that planet’s row should be toggled. If the moons are toggled on, then a MoonList
view will appear in the VStack
. This method is tied to the state property, showMoon
.
Next, complete the action by setting the showMoon
property. In the button’s action
callback, add the following code:
self.showMoon = self.toggleMoons(planet.name) ? nil : planet.name
This code either clears showMoon
if the user already pressed the button or sets it to the new planet if the user selects a different row.
Build and run the app. Tapping a row with a “moon disclosure” icon will show a cartoon map and a list of some that planet’s largest moons. The button also doubles in size to call attention to it. This is so the user knows where to tap to close the row.
This flashes the moon list view in and out, which is hardly a great user experience. Fortunately, adding a little animation is easy.
Start by creating a smooth animation for the button size. After the scaleEffect
modifier on the moon Image
, add the following modifier:
.animation(.default)
This adds a default animation to the scale effect. If you expand or collapse a row, the button will now grow or shrink smoothly. If you notice some issues in the instantaneous appearance and disappearance of the moon view, don’t worry. You’ll fix that in the Animating State Changes section below.
Animation Timing
The animation(_:)
modifier takes an Animation
parameter.
There are several options that you can use for an animation. The basic ones are simple timing curves that describe how the speed of animation changes over the duration. These all modify the changing attributes, interpolating smoothly between the start and end values.
You have the following options:
- .linear: This transitions the attribute from the start to end value evenly over time. This is a good timing curve for repeating animations, but it doesn’t look as natural as the eased functions.
- .easeIn: An eased-in animation starts off slow and picks up speed over time. This is good for animations that start from a resting point and finish off-screen.
- .easeOut: Eased-out animations start fast and end slow. This is good for animating something coming to a steady state or final position.
-
.easeInOut: Ease in and out curves combine both
easeIn
andeaseOut
. This is good for animations that start in one steady spot and end at another equilibrium. This is best for most applications. That is why this is timing curve used by.default
. - .timingCurve: This allows you to specify a custom timing curve. This is rarely needed and is out of the scope of this tutorial.
Most of the time, .default
will be good enough for your needs. If you need something more, one of the basic timing functions will give you a little extra refinement. Give them a try by replacing .default
with one of these to find out what’s best for you.
The graphs above show velocity over time for each of the timing curves. But how will the animations actually display? Here’s how each of the curves looks over time when you apply it to the scaleEffect
of the moon button.