0

I have an app with a few tabs, and on one of those there is a NavigationLink which nests a couple of times.

I want to be able to switch tabs, and when going back to the other tab to have unwound all links to the root view.

I have seen these: https://stackoverflow.com/a/67014642/1086990 and https://azamsharp.medium.com/unwinding-segues-in-swiftui-abdf241be269 but they seem to be focusing on unwinding when active on the view, not switching from it.

struct MyTabView: View {
 var body: some View {
  TabView {
   TabOne().tabItem { Image(systemName: "1.square") }
   TabTwo().tabItem { Image(systemName: "2.square") }
  }
 }
}

struct TabOne: View {
 var body: some View {
  Text("1")
 }
}

struct TabTwo: View {
 var body: some View {
  NavigationView {
   NavigationLink("Go to sub view") {
    TabTwoSub()
   }
  }
 }
}

struct TabTwoSub: View {
 var body: some View {
  Text("Tapping \(Image(systemName: "1.square")) doesnt unwind this view back to the root of the NavigationView")
   .multilineTextAlignment(.center)
 }
}

Maybe I've missed something fairly basic but nothing seems to come up from searches on unwinding views when switching tabs.

I tried using the NavigationLink(isActive: , destination: , label: ) from the other SO answer but couldn't get it working in the root MyTabView.

I thought about using UserDefaults to set a isActive bool state and if not try and unwind the navigation, but that didn't seem very swifty to do.

What is happening

enter image description here

markb
  • 1,100
  • 1
  • 15
  • 40

1 Answers1

1

You'll need to keep track of the tab selection in the parent view and then pass that into the child views so that they can watch for changes. Upon seeing a change in the selection, the child view can then reset a @State variable that change the isActive property of the NavigationLink.

class NavigationManager : ObservableObject {
    @Published var activeTab = 0
}

struct MyTabView: View {
    @StateObject private var navigationManager = NavigationManager()
    
    var body: some View {
        TabView(selection: $navigationManager.activeTab) {
            TabOne().tabItem { Image(systemName: "1.square") }.tag(0)
            TabTwo().tabItem { Image(systemName: "2.square") }.tag(1)
        }.environmentObject(navigationManager)
    }
}

struct TabOne: View {
    var body: some View {
        Text("1")
    }
}

struct TabTwo: View {
    @EnvironmentObject private var navigationManager : NavigationManager
    @State private var linkActive = false
    
    var body: some View {
        NavigationView {
            NavigationLink("Go to sub view", isActive: $linkActive) {
                TabTwoSub()
            }
        }.onChange(of: navigationManager.activeTab) { newValue in
            linkActive = false
        }
    }
}

struct TabTwoSub: View {
    var body: some View {
        Text("Tapping \(Image(systemName: "1.square")) doesnt unwind this view back to the root of the NavigationView")
            .multilineTextAlignment(.center)
    }
}

Note: this will result in a "Unbalanced calls to begin/end appearance transitions" message in the console -- in my experience, this is not an error and not something we have to worry about

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • thank you for that! I was already tracking the `currentTab` but stripped it for the questions simplicity! – markb Jan 02 '22 at 04:17