← All courses

Animations & Transitions

🗓 May 31, 2026 ⏱ 2 min read

Why SwiftUI animation is easy

Because SwiftUI already knows when your state changes, you mostly just say “animate this change” and it computes all the in-between frames for you. There is no manual frame-by-frame work.

Implicit animation with .animation

struct ExpandBox: View {
    @State private var expanded = false
    var body: some View {
        VStack {
            RoundedRectangle(cornerRadius: 12)
                .fill(.purple)
                .frame(height: expanded ? 200 : 80)
                .animation(.spring(), value: expanded)   // animate this property
            Button("Toggle") { expanded.toggle() }
        }
        .padding()
    }
}

.animation(_, value:) animates whenever the given value changes — a clean, targeted approach.

Explicit animation with withAnimation

To animate the change itself (rather than attach to a view), wrap the state change in withAnimation:

Button("Like") {
    withAnimation(.easeInOut(duration: 0.3)) {
        liked.toggle()
    }
}

Transitions: appear and disappear

When a view is added or removed, a transition controls how it enters/exits. Combine with conditional content:

if showDetail {
    DetailPanel()
        .transition(.move(edge: .bottom).combined(with: .opacity))
}
// trigger inside a withAnimation { showDetail.toggle() }

Animation curves

  • .easeInOut — smooth start and stop (good default).
  • .spring() — natural, bouncy motion.
  • .linear — constant speed (good for continuous things).

Looping and continuous animation

@State private var pulse = false
Circle().fill(.purple)
    .scaleEffect(pulse ? 1.2 : 1)
    .animation(.easeInOut(duration: 0.8).repeatForever(autoreverses: true), value: pulse)
    .onAppear { pulse = true }

Common mistakes

  • Animating everything — subtle motion feels premium; too much feels chaotic.
  • Forgetting the value: parameter so the animation doesn’t trigger.
  • Animating layout-heavy changes that cause jank — keep animations light.
Summary: Use .animation(_, value:) for property changes, withAnimation for state changes, and .transition for views appearing/disappearing. Choose a curve (.spring, .easeInOut) and keep motion subtle.