Search code examples
swiftswiftuiswiftui-animationswiftui-zstack

SwiftUI: Animate Transitions


How can I animate slide transitions between different views?

In following sample code I made a Picker that chooses which view to show and my goal is to have a transition that looks similar to the NavigationLink transition. At the moment it doesn't animate at all. If I add the .animation(.easeInOut(duration: 2)) modifier to the ZStack it animates a fade animation for 2 seconds but I don't understand why.

struct ContentView: View {

    enum WhichScreen: String, CaseIterable {
        case red, blue, green, yellow
    }

    @State private var whichScreen = WhichScreen.red

    var body: some View {
        VStack {
            Picker("screen", selection: $whichScreen.animation()) {
                ForEach(WhichScreen.allCases, id: \.self) { value in
                    Text(value.rawValue).tag(value)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            ZStack {
                Color.black
                switch whichScreen {
                case .red:
                    Color.red
                case .blue:
                    Color.blue
                case .green:
                    Color.green
                case .yellow:
                    Color.yellow
                }
            }
            .transition(.slide)
        }
    }
}

Solution

  • Do you actually need the ZStack with the black Color (which is never visible in your example snippet)? Without it the transition works out of the box (in the simulator, not in the SwiftUI preview):

    struct ContentView: View {
    
        enum WhichScreen: String, CaseIterable {
            case red, blue, green, yellow
        }
    
        @State private var whichScreen = WhichScreen.red
    
        var body: some View {
            VStack {
                Picker("screen", selection: $whichScreen.animation()) {
                    ForEach(WhichScreen.allCases, id: \.self) { value in
                        Text(value.rawValue).tag(value)
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
                Group {
                    switch whichScreen {
                    case .red:
                        Color.red
                    case .blue:
                        Color.blue
                    case .green:
                        Color.green
                    case .yellow:
                        Color.yellow
                    }
                }
                .transition(.slide)
            }
        }
    
    }