Wesley de Groot's Blog
Difference between animations in SwiftUI

Back

In this post, we will explore the difference between .animation() and withAnimation() and phaseAnimator() in SwiftUI. Both are used to create animations, but they serve different purposes and have different use cases.

What is .animation() and withAnimation() and phaseAnimation()?

.animation() is a view modifier in SwiftUI that applies an animation to changes in a view's state. It can be used to animate specific properties of a view, such as its position, scale, or opacity, when those properties change.

withAnimation() is a function that allows you to perform state changes with an animation. It can be used to wrap any state-changing code, and the changes will be animated automatically.

phaseAnimator() is a more advanced animation API that allows you to create complex animations by defining different phases of an animation and transitioning between them. It provides greater control over the animation process and can be used for more intricate animations.

In summary, use .animation() when you want to apply an animation to a specific view, and use withAnimation() when you want to animate state changes more generally.

.animation()

Example

struct ContentView: View {
    @State private var isScaled = false

    var body: some View {
        Circle()
            .scaleEffect(isScaled ? 1.5 : 1.0)
            .animation(.easeInOut(duration: 0.5))
            .onTapGesture {
                isScaled.toggle()
            }
    }
}

When isScaled changes, SwiftUI checks if the value passed to .animation() has changed.
If it has, the animation is applied to the changes in that view’s state.
You’re essentially telling the view how it should animate as its state updates.

Pros of .animation()

  • Simple and concise.

  • Declarative style fits right into SwiftUI’s architecture.

  • Great for chaining effects (e.g. scale, opacity, rotation).

Cons of .animation()

  • Limited control over timing and grouping.

  • Only works on the specific view it's attached to.

Use Case: Animating a Button Press

In this example, we have a button that scales up when pressed and scales back down when released. We use .animation() to apply the scaling animation to the button's scale effect.

struct ContentView: View {
    @State private var isActivated = false

    var body: some View {
        Button(action: {
            isActivated.toggle()
        }) {
            Text("Press Me")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
                .scaleEffect(isActivated ? 1.2 : 1.0)
                .animation(.easeInOut(duration: 0.2))
        }
    }
}

withAnimation()

withAnimation() is a function that allows you to perform state changes with an animation. It can be used to wrap any state-changing code, and the changes will be animated automatically.

Example

struct ContentView: View {
    @State private var isVisible = false

    var body: some View {
        VStack {
            Button("Toggle Visibility") {
                withAnimation(.easeInOut(duration: 0.5)) {
                    isVisible.toggle()
                }
            }

            if isVisible {
                Text("Hello, World!")
                    .transition(.slide)
            }
        }
    }
}

In this example, we use withAnimation() to wrap the state change of isVisible. When the button is pressed, the text will appear or disappear with a sliding transition. The animation is applied to the entire state change, including the transition of the text.

Pros of withAnimation()

  • Provides a simple way to animate state changes.

  • Can be used with any state-changing code, not just view properties.

  • Allows for more complex animations by combining multiple state changes.

Cons of withAnimation()

  • Less control over individual view animations.

  • Can lead to unexpected animations if not used carefully.

Use Case: Animating a View Transition

In this example, we use withAnimation() to wrap the state change of isVisible. When the button is pressed, the text will appear or disappear with a sliding transition. The animation is applied to the entire state change, including the transition of the text.

struct ContentView: View {
    @State private var isVisible = false

    var body: some View {
        VStack {
            Button("Toggle Visibility") {
                withAnimation(.easeInOut(duration: 0.5)) {
                    isVisible.toggle()
                }
            }

            if isVisible {
                Text("Hello, World!")
                    .transition(.slide)
            }
        }
    }
}

phaseAnimator()

phaseAnimator() is a more advanced animation API that allows you to create complex animations by defining different phases of an animation and transitioning between them. It provides greater control over the animation process and can be used for more intricate animations.

Example

import SwiftUI

struct ContentView: View {
    @State private var currentPhase: Int = 0

    var body: some View {
        PhaseAnimator([0, 1, 2]) { phase in
            Circle()
                .frame(width: phase == 0 ? 50 : (phase == 1 ? 100 : 150))
                .foregroundStyle(phase == 0 ? .blue : (phase == 1 ? .green : .red))
        } animation: { phase in
            switch phase {
            case 0: .easeIn(duration: 0.5)
            case 1: .spring(response: 0.6, dampingFraction: 0.8)
            default: .linear(duration: 0.3)
            }
        }
    }
}

This example uses phaseAnimator() to create a circle that changes its size and color based on the current phase. The animation is defined for each phase, allowing for more complex transitions.

Pros of phaseAnimator()

  • Provides fine-grained control over the animation process.

  • Allows for complex animations with multiple phases.

  • Can be used to create intricate animations that are difficult to achieve with .animation() or withAnimation().

  • Supports custom timing and easing functions for each phase.

Cons of phaseAnimator()

Use Case: Creating a Complex Animation

In this example, we use phaseAnimator() to create a circle that changes its size and color based on the current phase. The animation is defined for each phase, allowing for more complex transitions.

import SwiftUI

struct ContentView: View {
    @State private var phase: Int = 0

    var body: some View {
        PhaseAnimator([0, 1, 2]) { phase in
            Rectangle()
                .frame(width: phase == 0 ? 100 : 200, height: 50)
                .foregroundStyle(phase == 1 ? .blue : .red)
        } animation: { _ in
            .spring(response: 0.5, dampingFraction: 0.7)
        }
    }
}

Side-by-Side Comparison

Feature .animation() withAnimation() phaseAnimator()
Purpose Animates specific view properties Animates state changes Provides fine-grained control over the animation process.
Usage View modifier for specific views Function to wrap state changes Used to create intricate animations with multiple phases.
Control Limited to the view it's attached to More control over state changes Supports custom timing and easing functions for each phase.
Timing Fixed timing for the view Customizable timing for state changes Allows for complex animations with multiple phases.
Grouping Limited to the view's properties Can group multiple state changes Enables intricate animations that are difficult to achieve with .animation() or withAnimation().

When to Use Each

  • Use .animation() when you want to animate specific properties of a view, such as its position, scale, or opacity.

  • Use withAnimation() when you want to animate state changes more generally, such as showing or hiding views, or changing multiple properties at once.

  • Use phaseAnimator() when you need fine-grained control over the animation process, or when you want to create complex animations with multiple phases.

Conclusion

In summary, .animation() and withAnimation() are both powerful tools for creating animations in SwiftUI, but they serve different purposes. Use .animation() when you want to apply an animation to a specific view, and use withAnimation() when you want to animate state changes more generally. For more complex animations, consider using phaseAnimator(), which provides greater control over the animation process and allows for intricate animations with multiple phases.

Read more

Share


Share Bluesky Mastodon Twitter LinkedIn Facebook
x-twitter mastodon github linkedin discord threads instagram whatsapp bluesky square-rss sitemap