SwiftUI Field Guide

Animation Curves

In the real world, things move. On our screens, this is not really possible; we can only simulate movement. For example, if we draw a red box and move it one pixel to the right on every frame, it looks like the box is moving to the right. Timing curves help us control this movement.

If we always move at a constant speed, this is a linear animation using a linear timing curve. Here's what that looks like:

Code
struct CurveExample: View {    @State private var isTrailing = false        let animation = Animation.linear        var body: some View {        Color.red            .frame(width: 48, height: 48)            .frame(maxWidth: .infinity,                   alignment: isTrailing                       ? .trailing                       : .leading)            .contentShape(.rect)            .onTapGesture {                isTrailing.toggle()            }            .animation(animation,                       value: isTrailing)            .padding(20)    }}
Preview
Waiting to start Swift runtime…
Curve

To most of us, this looks a little uncanny. Objects in the real world move in a different way: typically, the velocity increases (by applying force) rather than the position. We can simulate this by using an easing curve. For example, the easeInOut timing curve starts slow, picks up speed, and slows down again at the end:

Code
struct CurveExample: View {    @State private var isTrailing = false        let animation = Animation.easeInOut        var body: some View {        Color.red            .frame(width: 48, height: 48)            .frame(maxWidth: .infinity,                   alignment: isTrailing                       ? .trailing                       : .leading)            .contentShape(.rect)            .onTapGesture {                isTrailing.toggle()            }            .animation(animation,                       value: isTrailing)            .padding(20)    }}
Preview
Waiting to start Swift runtime…
Curve
Ease InEase OutEase In Out

The type for expressing timing curves in SwiftUI is Animation. Above, we have seen cubic timing curves. These can all be expressed as unit curves, which we'll look at a bit further down.

Before iOS 17, the default timing curve was easeInOut with a duration of 0.35 seconds. For almost all built-in curves, we can specify a duration.

Springs

Springs model motion using velocity and physical parameters. We explore SwiftUI's spring presets, configuration, and completion on the Springs page.

Modifying Curves

We can modify animations by adding a delay, repeating them a fixed number of times or indefinitely, or by changing their speed.

Unit Curves

We can create custom timing curves as well. There is a static constructor on Animation that lets us specify a UnitCurve. Unit curves are cubic Bézier curves with a normalized coordinate space with values between 0 and 1. They can also overshoot by having values outside of that range.

In the interactive example below, we can play around with the control points of the unit curve and see what the animation looks like:

Curve

Drag either control point. Use the arrow keys for precise adjustments.

Preview
Start
End
Duration
1

Custom Curves

It's also possible to create completely custom curves using the CustomAnimation protocol. This gives us full control of the interpolation. We can also choose the merge behavior and specify what the velocity is at any given time.

Resources

Share Image

A Friendly Introduction to Spring Physics by Josh W. Comeau.

https://www.joshwcomeau.com/animation/a-friendly-introduction-to-spring-physics/