Search code examples
animationswiftuitransition

How to transition between two custom views based on state change?


I have a state variable in an ObservedObject that determines which of two custom views I show in SwiftUI.

I've messed around with .animation(.easeIn) in various locations and tried things with .withAnimation(), but I can't get anything to happen besides XCode complaints while experimenting. Regardless of where I put .animation() I either get a compile error no nothing happens when I run the code. Just flick from one view to another when I trigger a state change.

struct EventEditorView : View { /* SwiftUI based View */
    var eventEditorVC : EventEditorVC!

    @ObservedObject var eventEditorDataModel: EventEditorDataModel

    var body: some View {

        switch( eventEditorDataModel.editMode) {
        case .edit:
            EventEditModeView(eventEditorVC: eventEditorVC, eventEditorDataModel: eventEditorDataModel)
        case .view:
            EventViewModeView(eventEditorVC: eventEditorVC, eventEditorDataModel: eventEditorDataModel)
        }
    }
}

Solution

  • You can use a .transition on your elements and withAnimation when you change the value that affects their state:

    enum ViewToShow {
        case one
        case two
    }
    
    struct ContentView: View {
        @State var viewToShow : ViewToShow = .one
        
        var body: some View {
            switch viewToShow {
            case .one:
                DetailView(title: "one", color: .red)
                    .transition(.opacity.combined(with: .move(edge: .leading)))
            case .two:
                DetailView(title: "two", color: .yellow)
                    .transition(.opacity.combined(with: .move(edge: .top)))
            }
            Button("Toggle") {
                withAnimation {
                    viewToShow = viewToShow == .one ? .two : .one
                }
            }
        }
    }
    
    struct DetailView : View {
        var title: String
        var color : Color
        
        var body: some View {
            Text(title)
                .background(color)
        }
    }