Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Come back to a specific View in SwiftUI (popToViewController)

Is it possible in SwiftUI to come back to a specific view? Let's say I have three views this way:

struct View1: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: View2()) {
                    Text("Navigate to View2")
                }
                .navigationBarTitle("View1")
            }
        }
    }
}

struct View2: View {
    var body: some View {
        NavigationLink(destination: View3()) {
            Text("Navigate to View3")
        }
        .navigationBarTitle("View2")
    }
}

struct View3: View {
    var body: some View {
        Text("View3!")
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    View1()
  }
}
#endif

The navigation works back and forth:

View1->View2->View3
View3->View2->View1

Is it possible to directly come back to View1 from the View3? What I'm looking for is something similar to the UIKit

func popToViewController(_ viewController: UIViewController, 
                animated: Bool) -> [UIViewController]?
like image 385
matteopuc Avatar asked Aug 28 '19 21:08

matteopuc


1 Answers

Trying to solve this issue I ended up creating an open source project called swiftui-navigation-stack (https://github.com/biobeats/swiftui-navigation-stack). It contains the NavigationStackView, a view that mimics all the navigation behaviours of the standard NavigationView, adding some other features (all the features are explained in the readme of the repo). To answer the question here above we can use the NavigationStackView this way:

Let's pretend we have to implement a navigation like this:

View1 (push)-> View2 (push)-> View3 (push)-> View4 (pop)-> View2

First of all embed your first view in a NavigationStackView (as you'd do with the standard NavigationView):

struct RootView: View {
    var body: some View {
        NavigationStackView {
            View1()
        }
    }
} 

Let's create these simple views to build the example:

struct View1: View {
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 1")
                Spacer()
                PushView(destination: View2(), destinationId: "view2") {
                    Text("PUSH TO VIEW 2")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 2")
                Spacer()
                PushView(destination: View3()) {
                    Text("PUSH TO VIEW 3")
                }
            }
        }
    }
}

struct View3: View {
    var body: some View {
        ZStack {
            Color.gray.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 3")
                Spacer()
                PushView(destination: View4()) {
                    Text("PUSH TO VIEW 4")
                }
            }
        }
    }
}

struct View4: View {
    var body: some View {
        ZStack {
            Color.white.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 4")
                Spacer()
                PopView(destination: .view(withId: "view2")) {
                    Text("POP TO VIEW 2")
                }
            }
        }
    }
}

PushView and PopView let you navigate between views and, among other things, they let you specify an identifier for a view (so that you can come back to it if you need).

The following is the complete example, you can copy-paste it to xCode to try it yourself:

import SwiftUI
import NavigationStack

struct RootView: View {
    var body: some View {
        NavigationStackView {
            View1()
        }
    }
}

struct View1: View {
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 1")
                Spacer()
                PushView(destination: View2(), destinationId: "view2") {
                    Text("PUSH TO VIEW 2")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 2")
                Spacer()
                PushView(destination: View3()) {
                    Text("PUSH TO VIEW 3")
                }
            }
        }
    }
}

struct View3: View {
    var body: some View {
        ZStack {
            Color.gray.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 3")
                Spacer()
                PushView(destination: View4()) {
                    Text("PUSH TO VIEW 4")
                }
            }
        }
    }
}

struct View4: View {
    var body: some View {
        ZStack {
            Color.white.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 4")
                Spacer()
                PopView(destination: .view(withId: "view2")) {
                    Text("POP TO VIEW 2")
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        RootView()
    }
}

The result is:

enter image description here

like image 161
matteopuc Avatar answered Sep 27 '22 23:09

matteopuc