Difference between animations in SwiftUI
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()
orwithAnimation()
. -
Supports custom timing and easing functions for each phase.
Cons of phaseAnimator()
-
More complex to set up compared to
.animation()
andwithAnimation()
. -
Requires a deeper understanding of SwiftUI's animation system.
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
- Implementing Admob in SwiftUI • 7 minutes reading time.
- Difference between map, flatMap, compactMap • 4 minutes reading time.
- Appril Festival 2024 • 7 minutes reading time.
Share
Share Bluesky Mastodon Twitter LinkedIn Facebook