SwiftUI animation with switch statement

Viewed 1100

I understand how simple animations work in SwiftUI. However, I have a slightly more complex watchOS application. View state is handled by a switch statement:

struct ContentView: View {
    @EnvironmentObject private var state: AppState

    @State private var selection = 1

    var body: some View {
        Group {
            switch state.view {
            case .start:
                TabView(selection: $selection) {
                    ActivityView()
                        .tag(0)
                    StartView()
                        .tag(1)
                    SettingsView()
                        .tag(2)
                }
            case .workout:
                TabView(selection: $selection) {
                    TakeoffControlView()
                        .tag(0)
                    TakeoffView()
                        .tag(1)
                }
            }

            // ...
        }
    }
}

In another view I edit the view state:

struct StartView: View {
    @EnvironmentObject private var state: AppState

    var body: some View {
        Button(action: {
            state.view = .workout
        }, label: {
            Text("Start")
        })
    }
}

How can I add animations to transition between the different cases? I tried adding an animation to the Group, TabView and individual views without success. Obviously I wrapped the state change in withAnimation. However, I wasn't able to make it work. Any ideas how to make this work?

1 Answers

.transition() is just defining what the transition is , and to get the expected transition animation , you have to do the changes to SourceOfTruth inside withAnimation() { ... } block.

struct ContentView: View {
    @EnvironmentObject private var state: AppState

    @State private var selection = 1

    var body: some View {
        Group {
            switch state.view {
            case .start:
                TabView(selection: $selection) {
                    ActivityView()
                        .tag(0)
                    StartView()
                        .tag(1)
                    SettingsView()
                        .tag(2)
                }
                .transition(.slide)//<- here
                
            case .workout:
                TabView(selection: $selection) {
                    TakeoffControlView()
                        .tag(0)
                    TakeoffView()
                        .tag(1)
                }
                .transition(.slide)//<- here
            }

            // ...
        }
    }
}

struct StartView: View {
    @EnvironmentObject private var state: AppState

    var body: some View {
        Button(action: {
            withAnimation(.easeIn) {  //<- here
                state.view = .workout
            }
        }, label: {
            Text("Start")
        })
    }
}
Related