Disable animations on a specific view in SwiftUI using transactions

Animations in SwiftUI look great and make your app shine, but sometimes you want to disable animations on a specific view since it doesn’t look great when animating.

Compared to UIKit, SwiftUI makes it easier to create animated transitions between two states using the animation view modifier. You can see each animation as a transaction between a from and to state. We can alter this transaction using the transaction view modifier, which we’ll use in this article.

The problem definition

While I was working on a soon to be released Stock Analyzer app, I ran into the following animation for a bar chart graph:

The legend text animation does not look as great as we hoped.

The bar chart animation is also applied to the menu button, resulting in an animating button title. The “General and Administrative” text is too long for the button to put in one line, making the button grow in height.

I was not too fond of this animation, and I was looking for a way to disable animations for this specific menu button. A straightforward approach would be to disable the bar chart animation altogether, but I liked that one! Let’s dive into the solutions that I found.

Using the .animation(nil) view modifier

When searching on sites like Stack Overflow, you’ll soon get an old answer suggesting using the .animation(nil) view modifier to disable animations. However, when used in the latest version of Xcode, you’ll see the following warning:

Disable animations using the animation(nil) modifier is no longer supported.
The animation(nil) view modifier is deprecated, and you should no longer use it.

The deprecation warning makes it clear to us that we should try to use this method no longer. Since it’s deprecated, we’ll sooner or later have to replace this code, and we also want a warning-free project.

The suggestion is to use the animation(_:value:) modifier instead. It wasn’t immediately clear how the old view modifier would transform into this new one. Once again, suggested by others, I tried out the following modifier:

.animation(nil, value: UUID())

I couldn’t make this solution work, and I wouldn’t say I liked it. A view redraw will update the UUID, which means our modifier might run for no reason. Using a UUID in this way also makes it feel like a hack to me. Therefore, I continued my journey.

Using the transaction view modifier

I finally stumbled on the transaction view modifier that allows you to adjust a transaction between two states. A transaction contains the context of the current state-processing update, animated or not, meaning that this modifier calls even when you’re not animating the changes. You can verify this as follows:

.transaction { transaction in
    print(transaction.animation) // Prints: nil when not animated.
}

We can use this same transaction modifier to disable the animation as we would before:

.transaction { transaction in
    transaction.animation = nil
}

Any adjustments we make to the given transaction only apply to the animations used within the view containing the modifier.

The final result looks much better to me!

The legend animation is now disabled using the transaction modifier.

Conclusion

You can no longer disable animations in SwiftUI using the deprecated animation(nil) modifier. We can use the transaction modifier to create the same result and disable animations for a specific view in SwiftUI.

If you like to improve your SwiftUI knowledge even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.

Thanks!

 

Featured SwiftLee Jobs

Loading RSS Feed

Browse more Swift related Jobs, or add your own on SwiftLee Jobs