3

I'm working with SwiftUI and I have a starting page. When a user presses a button on this page, a modal sheet pops up.

In side the modal sheet, I have some code like this:

  NavigationLink(destination: NextView(), tag: 2, selection: $tag) {
            EmptyView()
    }

and my modal sheet view is wrapped inside of a Navigation View.

When the value of tag becomes 2, the view does indeed go to NextView(), but it's also presented as a modal sheet that the user can swipe down from, and I don't want this.

I'd like to transition from a modal sheet to a regular view.

Is this possible? I've tried hiding the navigation bar, etc. but it doesn't seem to make a difference.

Any help with this matter would be appreciated.

Evan
  • 1,892
  • 2
  • 19
  • 40
  • So if I understand correctly, you have `view A` which has a button upon pressing it `View B` is presented as modal, but when pressing something in `View B` you want `View A` to navigate to it? – Muhand Jumah Jun 10 '20 at 22:13
  • Hmm yeah I guess thats a good way of putting it. Like I watch to get out of the model view B and transition to some other view C (which is non modal) – Evan Jun 10 '20 at 23:19
  • By wrapping the modal sheet in a NavigationView you are assigning it its own UINavigationController and all navigation links within the modal sheet will be managed by that controller. You might be better using a Binding variable on your modal sheet to trigger a navigation link within the view that presented your sheet. But for it to work, you would probably need to first dismiss the modal sheet. – woneill1701 Jun 11 '20 at 00:02

1 Answers1

6

You can do this by creating an environmentObject and bind the navigationLink destination value to the environmentObject's value then change the value of the environmentObject in the modal view.

Here is a code explaining what I mean

import SwiftUI

class NavigationManager: ObservableObject{
    @Published private(set) var dest: AnyView? = nil
    @Published var isActive: Bool = false

    func move(to: AnyView) {
        self.dest = to
        self.isActive = true
    }
}

struct StackOverflow6: View {
    @State var showModal: Bool = false
    @EnvironmentObject var navigationManager: NavigationManager
    var body: some View {
        NavigationView {
            ZStack {
                NavigationLink(destination: self.navigationManager.dest, isActive: self.$navigationManager.isActive) {
                    EmptyView()
                }

                Button(action: {
                    self.showModal.toggle()
                }) {
                    Text("Show Modal")
                }
            }
        }
            .sheet(isPresented: self.$showModal) {
                secondView(isPresented: self.$showModal).environmentObject(self.navigationManager)
            }
    }
}

struct StackOverflow6_Previews: PreviewProvider {
    static var previews: some View {
        StackOverflow6().environmentObject(NavigationManager())
    }
}


struct secondView: View {
    @EnvironmentObject var navigationManager: NavigationManager
    @Binding var isPresented: Bool
    @State var dest: AnyView? = nil

    var body: some View {
        VStack {
            Text("Modal view")
            Button(action: {
                self.isPresented = false
                self.dest = AnyView(thirdView())
            }) {
                Text("Press me to navigate")
            }
        }
        .onDisappear {
            // This code can run any where but I placed it in `.onDisappear` so you can see the animation
            if let dest = self.dest {
                self.navigationManager.move(to: dest)
            }
        }
    }
}

struct thirdView: View {
    var body: some View {
        Text("3rd")
            .navigationBarTitle(Text("3rd View"))
    }
}

Hope this helps, if you have any questions regarding this code, please let me know.

Muhand Jumah
  • 1,726
  • 1
  • 11
  • 26