0

I have an app that has "two root navigation" structures. The first view (you can think of a login screen) contains navigation links to other detail views which are dismissable. One of the navigation links goes to a TabView, which I want to be a "new root" navigation view; meaning, a user should not be able to view the back button or swipe back to the first view. This TabView itself has navigation links, to other dismissables.

I used the .hideNavigationBar() modifier on the TabView to hide the navigation on this view, however the back button is still present. However if I switch to another tab, go to a detail, and dismiss that detail, the TabBar suddenly respects this hidden navigation bar. A minimal working example is pasted below:

struct BaseView: View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.gray
                VStack{
                    Text("Root Navigation View").padding()
                    NavigationLink(destination: RootTabNavView()) {
                        Text("To New Root View")
                    }.padding()
                    NavigationLink(destination: TestDetailView()) {
                        Text("To a detail view")
                    }.padding()
                }
            }
            .hideNavigationBar()
        }
    }
}

struct RootTabNavView: View {
    var body: some View {
        ZStack {
            TabView {
                TestTabView1()
                    .tabItem {
                        Text("1")
                    }
                TestTabView2()
                    .tabItem {
                        Text("2")
                    }
            }
        }
        .hideNavigationBar()
    }
}

struct TestTabView1: View {
    var body: some View {
        ZStack {
            Color.red
            Text("Test Tab View 1 (New Nav Root / Hidden Navigation)")
        }
        .hideNavigationBar()
    }
}

struct TestTabView2: View {
    var body: some View {
        ZStack {
            Color.green
            NavigationLink (destination: TestDetailView()) {
                Text("To a detail view")
            }
        }
        .hideNavigationBar()
    }
}

struct TestDetailView: View {
    var body: some View {
        ZStack {
            Color.purple
            Text("A Dismissable Detail")
        }
    }
}

struct BaseView_Previews: PreviewProvider {
    static var previews: some View {
        BaseView()
    }
}

When the app loads, the BaseView is shown with links to a TestDetailView and the RootTabNavView. When navigating to a TestDetailView we see the navigation bar at the top as intended, and dismissable back to the BaseView. However, when pressing the button to the RootTabNavView, the navigation tab is still present (letting the user swipe away the tabview). However if we switch to Tab 2, go to a detail view, and dismiss that detail view, all of a sudden the tab view has a hidden navigation bar.

What's more interesting is if I add to the RootTabNavView Navigation Link a isDetailLink(false) modifier, Tab 1 has a hidden navbar but when i switch to Tab 2 it reappears, only when i go to a detail and dismiss, it then hides again.

Is this a bug in SwiftUI? Am I misconfiguring something? Is .hideNavigationBar() or isDetailLink() behaving in ways I'm not aware of?

dovedevic
  • 673
  • 2
  • 14
  • 33
  • could you try using `.navigationBarBackButtonHidden()` in various places (eg: in RootTabNavView), instead of your `.hideNavigationBar()` (which does not compile for me) – workingdog support Ukraine Jul 10 '22 at 04:55
  • @workingdogsupportUkraine This does indeed hide the back button however the bar where the backbutton should be placed is still there (larger than usual navigation bar at the top) – dovedevic Jul 10 '22 at 19:29

1 Answers1

0

The TabView is designed to be root view, so might behave strange otherwise. Also it loads several tabs on start so having different modifiers in each for same purpose might conflict.

A better approach in this scenario is just replace initial NavigationView with new root view (TabView) with transition (which mimic navigation).

Tested with Xcode 13.4 / iOS 15.5

demo

Here is main part:

ZStack {
    if showRoot {
        RootTabNavView()
            .transition(.move(edge: .trailing))
    } else {
        NavigationView {
            ZStack {
                Color.gray
                VStack{
                    Text("Root Navigation View").padding()
                    Button(action: { showRoot = true }) {
                        Text("To New Root View")
                    }.padding()
                    NavigationLink(destination: TestDetailView()) {
                        Text("To a detail view")
                    }.padding()
                }
            }
            .navigationTitle("")        // << hide !!
            .navigationBarHidden(true)  // << hide !!
        }
        .transition(.asymmetric(insertion: .identity, removal: .move(edge: .leading)))
    }
}.animation(.default, value: showRoot)

Test module on GitHub

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • When viewing a detail from the tab view, the tab bar is still visible / navigable. Is this intended? Disableable? Hideable? – dovedevic Jul 10 '22 at 19:21