0

I have two Views, ViewA and ViewB. Both of them are inside of NavigationStack and they are inside of a TabView.

TabbarView:

import SwiftUI

struct TabbarView: View {
    var body: some View {
        TabView() {
            NavigationStack {
                ViewA()
            }
            .tabItem {Label("A", systemImage: "a.circle")}
            .tag(0)
            
            NavigationStack {
                ViewB()
            }
            .tabItem {Label("B", systemImage: "b.circle")}
            .tag(1)
        }
    }
}

struct TabbarView_Previews: PreviewProvider {
    static var previews: some View {
        TabbarView()
    }
}

Now on the ViewA, I am presenting a View (TheViewToBeLoadedView) modally (.fullScreenCover) with a new NavigationStack.

ViewA:

import SwiftUI

struct ViewA: View {
    @State private var isShowingCommonMenu = false
    @State private var isPresented = false
    @State private var sampleValue = 3
    
    var body: some View {
        VStack {
            Button {
                //MARK: Show Network Configure List
                self.isShowingCommonMenu.toggle()
            } label: {
                Text("GO")
            }
            .fullScreenCover(isPresented: $isShowingCommonMenu) {
                NavigationStack {
                    FullScreenModalView(isShowingCommonMenu: $isShowingCommonMenu) {
                        TheViewToBeLoadedView(sampleValue: $sampleValue)
                    }
                }
                .background(TransparentBackground())
            }
        }
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        .background(Color.orange)
        .padding()
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                HStack {
                    Button {
                        print("aaaaaaaa")
                    } label: {
                        Text("Button 1")
                    }
                    
                    Button {
                        print("aaaaaaaa")
                    } label: {
                        Text("Button 2")
                    }
                }
            }
        }
        
    }
}

struct ViewA_Previews: PreviewProvider {
    static var previews: some View {
        ViewA()
    }
}

I use FullScreenModalView and Load the view inside of a view which has transparent background. You can look at the code if you want to:

FullScreenModalView:

import SwiftUI

struct FullScreenModalView<Content: View>: View {
    @Binding var isShowingCommonMenu: Bool
    let content: () -> Content
    
    var body: some View {
        ZStack {
            Color.black.opacity(0.4)
                .edgesIgnoringSafeArea(.all)
                .onTapGesture {
                    //Dismiss the modal view when the user taps outside of it
                    dismiss()
                }
            
            VStack {
                content()
            }
            .cornerRadius(10)
            .overlay(
                Button {
                    dismiss()
                } label: {
                    DismissButton()
                }, alignment: .topTrailing)
        }
        .ignoresSafeArea(.keyboard)
        .edgesIgnoringSafeArea(.all)
        .background(TransparentBackground())
    }
    
    private func dismiss() {
        isShowingCommonMenu = false
    }
}

struct FullScreenModalView_Previews: PreviewProvider {
    static var previews: some View {
        FullScreenModalView(isShowingCommonMenu: .constant(true)) {
            Text("This is a custom preview view")
        }
    }
}
struct TransparentBackground: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        DispatchQueue.main.async {
            view.superview?.superview?.backgroundColor = .clear
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

struct DismissButton: View {
    var body: some View {
        ZStack {
            Circle()
                .frame(width: 30, height: 30)
                .foregroundColor(.white)
                .opacity(0.6)
            Image(systemName: "xmark")
                .imageScale(.medium)
                .frame(width: 44, height: 44)
                .foregroundColor(Color(.label))
        }
    }
}

It works perfectly, now I can navigate to ViewADetails from this TheViewToBeLoadedView by navigationDestination(isPresented.

TheViewToBeLoadedView:

import SwiftUI

struct TheViewToBeLoadedView: View {
    @Binding var sampleValue: Int
    @State private var isShowingDetails = false
    
    var body: some View {
        Button {
            isShowingDetails.toggle()
        } label: {
            Text("Go to the Details")
        }
        .frame(width: 300, height: 100, alignment: .center)
        .background(Color.yellow)
        .navigationDestination(isPresented: $isShowingDetails) {
            ViewADetails()
        }
    }
}

struct TheViewToBeLoadedView_Previews: PreviewProvider {
    static var previews: some View {
        TheViewToBeLoadedView(sampleValue: .constant(2))
    }
}

But when I navigate to the DetailsViewA you can see it goes out of the Tabbar, because of the new NavigationStack.

Is it possible to get the current NavigationStack on the ViewA and use that instead of using a new NavigationStack?

Thanks!

enter image description here enter image description here enter image description here

Tulon
  • 4,011
  • 6
  • 36
  • 56
  • No, this is standard behavior too. What you likely want is a “Router” of sorts. If you research VIPER you can read about the concept. It is a good way to get complex navigation organized especially if in the long term plan for your app you plan on introducing things like going to certain views when the user taps a widget or notification. – lorem ipsum Apr 13 '23 at 11:47

0 Answers0