Lukas Pistrol Logo

Lukas Pistrol

SwiftUI: Disable animations

Animations are great for enhancing the user experience (UX) of your app. SwiftUI has a lot of built-in animations in its components already and it's easier than ever to add custom animations to your views as well. There is, however, one problem that you might run into when using the animation modifier: it will apply to all subviews as well. This can be a problem if you just want to animate a single property of a view (e.g. the opacity) and not other properties like the size or position.

Prior to iOS 15

Before iOS 15 there was an easy way to disable all animations for a view by setting the animation modifier to nil:

MyView()
    .animation(nil)

While this is still possible and working in iOS 15 and above (even iOS 17) it is now marked as deprecated and will result in a warning in Xcode:

'animation' was deprecated in i0S 15.0: Use withAnimation or animation(_:value:) instead

While you can still use this modifier and provide a value to it, there might be some situations where you might not have a specific value that drives the animation (e.g. on some default components that change on user interaction like Menu). So how can we do this properly?

iOS 15 and above

As it turns out there is a modifier called transaction available that passes a Transaction object to its closure. This struct has an optional property called animation that you then can set to nil.

MyView()
    .transaction { transaction in
        transaction.animation = nil
    }

This will result in the same behavior as the deprecated animation(nil) modifier.

You can even make it a bit less verbose by not providing the transaction parameter name:

MyView()
    .transaction { $0.animation = nil }

Finally you can create a custom view modifier in conjunction with a view extension that does this for you:

struct DisableAnimationsViewModifier: ViewModifier {
    func body(content: Content) -> some View {
        content.transaction { $0.animation = nil }
    }
}

extension View {
    func disableAnimations() -> some View {
        modifier(DisableAnimationsViewModifier())
    }
}

Alternatively you can just create a view extension that returns the view wrapped in a transaction modifier as well:

extension View {
    func disableAnimations() -> some View {
        transaction { $0.animation = nil }
    }
}

Now you can simply add disableAnimations() to any view that you want to disable animations for:

MyView()
    .disableAnimations()

Conclusion

While the animation modifier is deprecated in iOS 15 and above, there is still a way to disable animations for a view and its subviews. It's just a bit more verbose than before. Hopefully this helps you to improve the UX of your app by adding animations where they make sense and disabling them where they don't.

If you have any questions or feedback feel free to reach out to me on X (formerly Twitter).

Also make sure to check out the recommended article below or browse all other SwiftUI articles.

Another article you might like: