Skip to main content

How to run a completion callback when an animation finishes

About 2 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to run a completion callback when an animation finishes 관련

SwiftUI by Example

Back to Home

How to run a completion callback when an animation finishes | SwiftUI by Example

How to run a completion callback when an animation finishes

Updated for Xcode 15

New in iOS 17

SwiftUI’s withAnimation() function can optionally be given a completion callback with code to run when the animation finishes. This might be where you adjust some program state, but you can also use it as a simple way to chain animations together – to animate one thing, then animate something else afterwards.

For example, this makes a button scale up then fade out:

struct ContentView: View {
    @State private var scaleUp = false
    @State private var fadeOut = false

    var body: some View {
        Button("Tap Me!") {
            withAnimation {
                scaleUp = true
            } completion: {
                withAnimation {
                    fadeOut = true
                }
            }
        }
        .scaleEffect(scaleUp ? 3 : 1)
        .opacity(fadeOut ? 0 : 1)
    }
}

Download this as an Xcode projectopen in new window

A button that scales up then disappears when pressed.
A button that scales up then disappears when pressed.

There is one little subtlety here that might hit you: if you’re using a spring animation it’s possible there’s a very long tail of movement at the end, where your animation is moving small fractions of a point that are imperceptible to the user.

The default behavior of withAnimation() is to consider the animation complete even with that long tail of tiny movement still happening, but if you wanted it to be 100% finished you can override the default like this:

struct ContentView: View {
    @State private var scaleUp = false
    @State private var fadeOut = false

    var body: some View {
        Button("Tap Me!") {
            withAnimation(.bouncy, completionCriteria: .removed) {
                scaleUp = true
            } completion: {
                withAnimation {
                    fadeOut = true
                }
            }
        }
        .scaleEffect(scaleUp ? 3 : 1)
        .opacity(fadeOut ? 0 : 1)
    }
}

Download this as an Xcode projectopen in new window

A button that scales up then disappears when pressed.
A button that scales up then disappears when pressed.

I probably wouldn’t recommend that unless you had a very specific use case – the default setting ought to be fine.

Tips

For more complex effects, consider using a phase animator instead of animation completion closures.

Similar solutions…
How to start an animation immediately after a view appears | SwiftUI by Example

How to start an animation immediately after a view appears
How to create an explicit animation | SwiftUI by Example

How to create an explicit animation
How to create a spring animation | SwiftUI by Example

How to create a spring animation
How to delay an animation | SwiftUI by Example

How to delay an animation
How to run some code when state changes using onChange() | SwiftUI by Example

How to run some code when state changes using onChange()

이찬희 (MarkiiimarK)
Never Stop Learning.