Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fatal error: No ObservableObject of type NavigationStack found. #13

Closed
blainesolomon opened this issue Mar 21, 2020 · 2 comments
Closed

Comments

@blainesolomon
Copy link

blainesolomon commented Mar 21, 2020

Open curiosity: Is there a way to use this inside of a modal or nav view? (Works well otherwise)

If I attempt either, I get the following error:

Fatal error: No ObservableObject of type NavigationStack found.

I'm down to try anything as a potential workaround

@matteopuc
Copy link
Owner

Hi @blainesolomon, thanks for asking. Your question is actually very interesting. In SwiftUI a modal view (presented with the .sheet modifier) opens a new view hierarchy. A NavigationStackView works for its view hierarchy. I mean: if you do something like:

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

That NavigationStackView will work for that specific hierarchy. But if you want to have a navigation flow in a modal view you can wrap your modal content in a new NavigationStackView, basically creating another navigation flow. Take a look at this example:

import SwiftUI
import NavigationStack

struct ContentView : View {
    var body: some View {
        NavigationStackView {
            ZStack {
                Color.green.edgesIgnoringSafeArea(.all)
                PushView(destination: Child()) {
                    Text("PUSH!")
                }
            }
        }
    }
}

struct Child : View {
    @State private var modalIsActive = false

    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("Hello World")
                    .sheet(isPresented: $modalIsActive) {
                        NavigationStackView {
                            ModalView()
                        }
                    }
                PopView {
                    Text("POP")
                }
                Button(action: {
                    self.modalIsActive = true
                }, label: {
                    Text("OPEN MODAL")
                })
            }
        }
    }
}

struct ModalView : View {
    var body: some View {
        ZStack {
        Color.red.edgesIgnoringSafeArea(.all)
            VStack {
                Text("MODAL VIEW")
                PushView(destination: ModalChild()) {
                    Text("PUSH TO MODAL CHILD")
                }
            }
        }
    }
}

struct ModalChild : View {
    var body: some View {
        ZStack {
            Color.blue.edgesIgnoringSafeArea(.all)
            VStack {
                Text("MODAL CHILD")
                PopView {
                    Text("POP")
                }
            }
        }
    }
}

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

The result is:

Mar-22-2020 00-18-47

If you want, instead, to use the NavigationStackView inside the SwiftUI standard NavigationView things get complicated because every time you use the standard NavigationLink the framework creates a new view hierarchy. For example, if you write something like:

struct ContentView : View {
    var body: some View {
        NavigationStackView {
            NavigationView {
                ZStack {
                    Color.green.edgesIgnoringSafeArea(.all)
                    VStack {
                        PushView(destination: Child()) {
                            Text("PUSH WITH NavigationStackView!")
                        }
                        NavigationLink(destination: Child()) {
                            Text("PUSH WITH SwiftUI Standard navigation!")
                        }
                    }
                }
            }
        }
    }
}

struct Child : View {
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("Hello World")
                PopView {
                    Text("POP")
                }
            }
        }
    }
}

and you "push" with the standard NavigationLink, you won't be able to come back with the PopView. You can wrap your Child view in a new NavigationStackView as in:

struct ContentView : View {
    var body: some View {
        NavigationStackView {
            NavigationView {
                ZStack {
                    Color.green.edgesIgnoringSafeArea(.all)
                    VStack {
                        PushView(destination: Child()) {
                            Text("PUSH WITH NavigationStackView!")
                        }
                        NavigationLink(destination: NavigationStackView { Child() }) {
                            Text("PUSH WITH SwiftUI Standard navigation!")
                        }
                    }
                }
            }
        }
    }
}

In this case you'll be able to push view from the child view on, but you won't be able to come back with the PopView to the ContentView because the two views belong to two different view hierarchies.

Matteo

@mustafaozhan
Copy link
Contributor

@matteopuc @blainesolomon
you need to send your environmentObject to sheet like this

        .sheet(
            isPresented: $isBarShown,
            content: {
                BarView(
                    isBarShown: $isBarShown,
                    onDismiss: { observable.viewModel.verifyCurrentBase() }
                ).environmentObject(navigationStack)
            }
        )

After that it works perfectly fine 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants