FREE TRIAL: Accelerate your app development career with Hacking with Swift+! >>

How to override animations with transactions

Paul Hudson    @twostraws   

Updated for Xcode 13.0

SwiftUI provides a withTransaction() function that allows us to override animations at runtime, for example to remove an implicit animation and replace it with something custom.

For example, this code toggles some text between small and large sizes, animating all the way because it has an implicit animation attached:

struct ContentView: View {
    @State private var isZoomed = false

    var body: some View {
        VStack {
            Button("Toggle Zoom") {
                isZoomed.toggle()
            }

            Spacer()
                .frame(height: 100)

            Text("Zoom Text")
                .font(.title)
                .scaleEffect(isZoomed ? 3 : 1)
                .animation(.easeInOut(duration: 2), value: isZoomed)
        }
    }
}

Download this as an Xcode project

Transactions allow us to override existing animations on a case by case basis. For example, you might decide that in one particular circumstance you want the text’s animation to happen in a fast, linear way rather than it’s existing animation.

To do that, first create a new Transaction instance using whatever animation you want, then set its disablesAnimations value to true so you override any existing animations that would apply. When you’re ready, call withTransaction() using your transaction object, then go ahead and adjust all the state you want to change – it will all be animated using your transaction.

To demonstrate this in action, here’s our same text scaling example code except using a transaction to insert a custom animation that overrides the implicit one:

struct ContentView: View {
    @State private var isZoomed = false

    var body: some View {
        VStack {
            Button("Toggle Zoom") {
                var transaction = Transaction(animation: .linear)
                transaction.disablesAnimations = true

                withTransaction(transaction) {
                    isZoomed.toggle()
                }
            }

            Spacer()
                .frame(height: 100)

            Text("Zoom Text")
                .font(.title)
                .scaleEffect(isZoomed ? 3 : 1)
                .animation(.easeInOut(duration: 2), value: isZoomed)
        }
    }
}

Download this as an Xcode project

For even more control you can attach a transaction() modifier to any view you want, allowing you to override any transactions that apply to the view.

For example, we could add a second zooming text view to our example, still using a transaction to trigger the zoom animation, but this time we’re going to use the transaction() modifier on the second text view so we disable any transactions on that one view – we’re overriding the override, in effect:

struct ContentView: View {
    @State private var isZoomed = false

    var body: some View {
        VStack {
            Button("Toggle Zoom") {
                var transaction = Transaction(animation: .linear)
                transaction.disablesAnimations = true

                withTransaction(transaction) {
                    isZoomed.toggle()
                }
            }

            Spacer()
                .frame(height: 100)

            Text("Zoom Text 1")
                .font(.title)
                .scaleEffect(isZoomed ? 3 : 1)

            Spacer()
                .frame(height: 100)

            Text("Zoom Text 2")
                .font(.title)
                .scaleEffect(isZoomed ? 3 : 1)
                .transaction { t in
                    t.animation = .none
                }
        }
    }
}

Download this as an Xcode project

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Get started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.