Springs
Springs are the new default animation as of iOS 17. At first, we might think of springs as something that bounces. However, for animations, the biggest advantage is that springs are a model of the physical world and take velocity into account. Similar to UIKit Dynamics, they are a physical simulation of a motion system. The biggest benefit compared to bezier curves is that we can retarget a spring animation while keeping the velocity. We'll say more about this in interruptible animations.
Springs can arrive at their target value and still oscillate for a bit without us really noticing it visually. The animation is said to be logically complete. This is something that shows up in the API as well, and when we add completion handlers, we can work with this property as well.
struct CurveExample: View { @State private var isTrailing = false let animation = Animation.spring 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) }}
SwiftUI also has a .bouncy spring. Depending on the use case, this can be especially nice when moving objects on the screen, as it slightly overshoots.
struct CurveExample: View { @State private var isTrailing = false let animation = Animation.bouncy 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) }}
Note: Overshooting animations are not always a great choice. For example, when we're animating a color or opacity, overshooting might have unexpected effects. Animations based on curves might be a better fit there.
We can also configure the physics simulation behind spring animation ourselves by providing mass, damping and stiffness. Play around with the parameters to see what they do:
struct CurveExample: View { @State private var isTrailing = false let animation = Animation.spring(Spring(mass: 1, stiffness: 100, damping: 10)) 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) }}
There are also convenience initializers on Spring that lets us specify duration and bounciness. These are used to then compute mass, damping and stiffness.
Note: There is also the older .interpolatingSpring static constructor, which has been available since iOS 13. This is a different type of spring animation that does not start from the existing velocity when retargeting. Instead, it blends the two animations.
For linear and easing animations, unit curves, and animation modifiers, see Animation Curves.
Resources

A Friendly Introduction to Spring Physics by Josh W. Comeau.
https://www.joshwcomeau.com/animation/a-friendly-introduction-to-spring-physics/