Building Engaging User Interfaces with SwiftUI

Mar 12 2025 · Swift 5.9, iOS 17.0, XCode 15.0

Lesson 01: Mastering SwiftUI Animations

Exploring Animation Types

Episode complete

Play next episode

Next
Transcript

Change the animation for the icon to:

.animation(
  .interpolatingSpring(
    mass: 1,
    stiffness: 100,
    damping: 10,
    initialVelocity: 0
  ),
  value: showTerminal
)

When you run the app, you see the icon bounces a bit at the end. The icon continues a bit past the destination, slides back, and then bounces around the final position a bit before stopping.

You use four parameters to define a spring animation:

  • mass: Controls how long the system “bounces”.
  • stiffness: Controls the initial movement’s speed.
  • damping: Controls how rapidly the system slows and stops.
  • initialVelocity: Gives an extra initial motion.

To see how these parameters affect the animation, change each one at a time.

First, increase the mass to 100 and view the animation.

Next, change the mass to 0.5 and view the animation.

You can see that increasing the mass causes the animation to last longer and bounce further on each side of the endpoint. A smaller mass stops faster and travels a shorter distance past the endpoints on each bounce.

Next, double the stiffness. Then halve it. You see increasing the stiffness causes the bounce to move farther past the endpoints but with less effect on the animation’s duration.

The other parameters are more intuitive. Increasing the damping smooths and ends the animation faster. Increasing the initialVelocity causes the animation to bounce farther. A negative initialVelocity can move the animation in the opposite direction until it overcomes the initial velocity.

Unless you’re a physicist, the animation’s physical model doesn’t intuitively map to the results. SwiftUI introduces a more intuitive way to define a spring animation. The underlying model doesn’t change, but you can specify parameters to the model better related to how you want the animation to appear in your app. Change your animation to:

.animation(
  .spring(
    response: 0.55,
    dampingFraction: 0.45,
    blendDuration: 0
  ),
  value: showTerminal
)

If you didn’t dampen the animation, the position would begin at the initial value, move to the final value, and then return to the initial value. This loop would complete one oscillation. The response parameter defines the time to complete that single oscillation if you don’t dampen the system, which is where you set the dampingFraction to zero. It allows you to tune the animation’s duration.

The dampingFraction controls how quickly the “springiness” stops. A value of 0 never stops. A value of 1 or more causes the system to stop without oscillation. This overdamped state resembles an eased animation. You usually use a value between 0 and 1, which results in some oscillation before the animation ends. Greater values slow down faster.

The blendDuration parameter provides a control for blending the length of the transition among different animations. It only comes into use if you change the parameters during animation or combine multiple spring animations. A 0 value turns off blending.

Removing and Combining Animations

In SwiftUI’s initial release, animations could sometimes occur where you didn’t want them. Adding the value parameter to the animation(_:value:) addresses much of this problem. There still might be times that you want to apply no animation. You do this by passing a nil animation type to the animation(_:value:) method.

Still in FlightInfoPanel.swift, add the following modifier after the .rotationEffect modifier:

.scaleEffect(showTerminal ? 1.5 : 1.0)

This change adds a scaling of 1.5 times the icon’s original size when showing the terminal map. If you view the animation, you see the button grows in sync with the rotation. An animation affects all state changes that occur on the element where you apply the animation.

Next, add the following code between the rotationEffect() and scaleEffect() methods:

.animation(nil, value: showTerminal)

Trigger the animation again. You should see a rapid fade-out/fade-in effect on the rotation, but the size change still shows a spring animation. Again, think of an animation as affecting all state changes attached to it.

You can combine different animations by using .animation(_:value:) multiple times. Change the animation on the rotationEffect() from nil to:

.animation(.linear(duration: 1), value: showTerminal)

You see the two animations take place simultaneously but produce different effects. The rotation shows a linear animation, while the scaling of the icon shows a spring animation. Also, note that SwiftUI handles the animations’ different durations with no problems.

Explicit Animations

So far, you’ve applied animations only to view elements that changed. This produces an implicit animation, one triggered by a state change. You can also produce explicit animations where you attach the animation to the change.

Remove all .animation(_:value:) modifiers from the images. Change the action of the button that toggles showing the terminal map to:

withAnimation(
  .spring(
    response: 0.55,
    dampingFraction: 0.45,
    blendDuration: 0
  )
) {
  showTerminal.toggle()
}

You wrap the state change to showTerminal inside a withAnimation(_:_:) method. This call uses a spring animation, but you could pass any animation to this function.

Using withAnimation(_:_:) applies the animation to every visual change that results from the state change in the closure. Between the start of the HStack and the Text view inside the button, add the following code:

Image(systemName: "airplane.circle")
  .imageScale(.large)
  .padding(10)
  .rotationEffect(.degrees(showTerminal ? 90 : 270))
Spacer()

Notice the animation happens to both icons. Explicit animations simplify the code when you wish to use a single animation type on multiple changes that result from a state change. Be careful, because SwiftUI applies the animation for all state changes. If another property relied on the value of showTerminal, the animation would also apply to that property.

Now that you’ve learned the basics of SwiftUI animations, you’ll explore combining multiple animations and animating paths in the next section.

See forum comments
Cinema mode Download course materials from Github
Previous: Starting with SwiftUI Animations Next: Multiple Animations & Animating Paths