How to run a completion callback when an animation finishes
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)
}
}
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)
}
}
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.