tanaschita.com

SwiftUI provides built-in support for animations. In many cases, adding animations only requires attaching an animation to a state change.

There are two common ways to do this:

  1. animation(_:value:) view modifier for animations when a certain state value changes
  2. withAnimation(_:_:) global function which we can use to apply state changes and create animations for all views affected by them

In this article, we'll look at how both approaches work and when to use each of them.

Let's dive in.

Sponsorship logo

Architecture & Design Patterns for iOS

This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.

LEARN MORE

Animating a view with animation(_:value:)

The animation(_:value:) view modifier is useful when we need to animate a view every time a specific value changes. We can use it as follows:

@State private var color = Color.brown

var body: some View {

Button("Change color") {

color = color == .brown ? .mint : .brown

}

.padding(20)

.background(color)

.foregroundStyle(.white)

.animation(.easeInOut, value: color)

}

The modifier does not animate the value itself. The value parameter defines which state change should trigger the animation. Whenever the value of color changes, SwiftUI animates all affected updates.

This type of animation is often referred to as an implicit animation because the view automatically animates when the specified state changes.

We can also disable animation for a view by passing nil:

.animation(nil, value: color)

This is handy when we want to opt a specific view out of an animation that would otherwise be inherited from a parent.

Animating state changes with withAnimation

Instead of attaching the animation to a view, we can also explicitly animate state changes by using the withAnimation global function:

@State private var color = Color.brown

var body: some View {

Button("Change color") {

withAnimation(.easeInOut) {

color = color == .brown ? .mint : .brown

}

}

.padding(20)

.background(color)

.foregroundStyle(.white)

}

In this approach, the animation is applied to all view updates caused by the state changes inside the withAnimation closure.

Reacting when an animation finishes

withAnimation additionally provides a completion handler (iOS 17+), so we can run code once the animation settles:

withAnimation(.easeInOut) {

color = color == .brown ? .mint : .brown

} completion: {

print("Color animation finished")

}

This is useful for chaining animations or triggering follow-up actions after a transition completes.

Choosing between both approaches

Both approaches can often achieve the same visual result, but they are useful in different situations.

animation(_:value:) works well when a specific view should always animate in response to a particular state change.

withAnimation is often the better choice when multiple state changes should animate together or when we want more explicit control over when animations occur.

Read the original on tanaschita.com ↗