6
votes

I am currently using SwiftUI Beta 5. I have a workflow which involves navigating through a series of views. The last view involves an operation which populates a load of data into the app and ends that particular workflow.

Once the data has been downloaded, the user should be able to start new workflow(s). I would like to "forget" about the old NavigationView, since there is no use in going back through the navigation stack once the workflow has completed. Instead, I would like to then navigate to a "launch" view which effectively becomes the root of a new navigation view.

How can one view within a navigation stack be used to navigate to another view with a different NavigationView (and hence becomes a root for a new navigation stack) using SwiftUI NavigagationViews?

1
Have you seen this stackoverflow.com/a/57513566/7786555 Also, when I tried to do it in beta 5 in the past, there was no easy way. I need to revisit it now that we have beta 6.kontiki
@kontiki, Thanks, yes, I saw that. Moving directly back to the root is an option. (By the poster's own admission, it can get a bit clunky if there are many views in the stack.) I am interested in navigating "sideways" to a new root view, rather than moving back to the original root.Andy Thomas

1 Answers

3
votes

First, sorry I wanted to post a simple comment but not enough reputation point :(

I just updated my way to go back to the root you at stackoverflow.com/a/57513566/7786555

You actually gave me the idea with your comment for new way to go back to the root. Having a new root view. If you force the refresh of your struct view managing the root view then it will automatically do what you want. Here under is only going back to the root (without animation). You can adapt the example to change the root view (instead of using the same) to suit your need.

struct DetailViewB: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    @State var fullDissmiss:Bool = false
    var body: some View {
        SGNavigationChildsView(fullDissmiss: self.fullDissmiss){
            VStack {
                Text("This is Detail View B.")

                Button(action: { self.presentationMode.wrappedValue.dismiss() } )
                { Text("Pop to Detail View A.") }

                Button(action: {
                    self.fullDissmiss = true
                } )
                { Text("Pop two levels to Master View with SGGoToRoot.") }
            }
        }
    }
}

struct DetailViewA: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    @State var fullDissmiss:Bool = false
    var body: some View {
        SGNavigationChildsView(fullDissmiss: self.fullDissmiss){
            VStack {
                Text("This is Detail View A.")

                NavigationLink(destination: DetailViewB() )
                { Text("Push to Detail View B.") }

                Button(action: { self.presentationMode.wrappedValue.dismiss() } )
                { Text("Pop one level to Master.") }

                Button(action: { self.fullDissmiss = true } )
                { Text("Pop one level to Master with SGGoToRoot.") }
            }
        }
    }
}

struct MasterView: View {
    var body: some View {
        VStack {
            Text("This is Master View.")
            NavigationLink(destination: DetailViewA() )
            { Text("Push to Detail View A.") }
        }
    }
}

struct ContentView: View {

    var body: some View {
        SGRootNavigationView{
            MasterView()
        }
    }
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

struct SGRootNavigationView<Content>: View where Content: View {
    let cancellable = NotificationCenter.default.publisher(for: Notification.Name("SGGoToRoot"), object: nil)

    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    @State var goToRoot:Bool = false

    var body: some View {
        return
            Group{
            if goToRoot == false{
                NavigationView {
                content()
                }
            }else{
                NavigationView {
                content()
                }
            }
            }.onReceive(cancellable, perform: {_ in
                DispatchQueue.main.async {
                    self.goToRoot.toggle()
                }
            })
    }
}

struct SGNavigationChildsView<Content>: View where Content: View {
    let notification = Notification(name: Notification.Name("SGGoToRoot"))

    var fullDissmiss:Bool{
        get{ return false }
        set{ if newValue {self.goToRoot()} }
    }

    let content: () -> Content

    init(fullDissmiss:Bool, @ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.fullDissmiss = fullDissmiss
    }

    var body: some View {
        return Group{
            content()
        }
    }

    func goToRoot(){
        NotificationCenter.default.post(self.notification)
    }
}