NavigationLink does not append to path inside NavigationSplitView/NavigationStack

1k Views Asked by At

The following code shows that $path is always 0, despite tapping a NavigationLink inside the stack. That means that when I select a panel, and tap on the navigation link to go to 'firstPanel subview', then select a new panel, it does not reset the NavigationStack's path.

If I use the new .navigationDestination API then it works, but I was under the impression that the older NavigationLink without value: should work too since it's not deprecated. This is on iOS 16.4.

Ideas:

  • I'm not binding to $path properly somehow
  • The NavigationStack doesn't understand its root view
  • I don't think I need a separate NavigationStack per panel?
  • Maybe I do need to use .navigationDestination everywhere? Perhaps it's intended that this NavigationLink doesn't modify the stack's path? Seems odd. I see older NavigationLinks in the FoodTruck sample app.
  • This may be unrelated to NavigationSplitView, just NavigationStack.

Screenshot showing firstPanel subview remaining after selecting secondPanel

import SwiftUI

enum Panel: String, Hashable {
    case firstPanel, secondPanel
}

struct ContentView: View {
    @State private var selection: Panel? = .firstPanel
    @State private var path = NavigationPath()
        
    var body: some View {
        NavigationSplitView {
            List(selection: $selection) {
                NavigationLink(value: Panel.firstPanel) {
                    Text(Panel.firstPanel.rawValue)
                }
                
                NavigationLink(value: Panel.secondPanel) {
                    Text(Panel.secondPanel.rawValue)
                }
            }
            .listStyle(.sidebar)
            .navigationTitle("MyApp")
        } detail: {
            NavigationStack(path: $path) {
                switch selection ?? .firstPanel {
                case .firstPanel:
                    NavigationLink {
                        Text("This is \(Panel.firstPanel.rawValue) subview") // <-- navigate to here, then tap secondPanel
                    } label: {
                        Text("Go to \(Panel.firstPanel.rawValue) subview")
                    }
                case .secondPanel:
                    NavigationLink {
                        Text("This is \(Panel.secondPanel.rawValue) subview")
                    } label: {
                        Text("Go to \(Panel.secondPanel.rawValue) subview")
                    }
                }
            }
        }
        .onChange(of: selection) { _ in
            print(path.count) // <-- always prints 0
            path.removeLast(path.count)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewDevice("iPad Pro (11-inch) (4th generation)")
            .previewInterfaceOrientation(.landscapeLeft)
    }
}

Thanks!

1

There are 1 best solutions below

0
On

In your code there is nothing that can be appended on path. SwiftUI needs some kind of data to actually append to path. NaviationLink examples on SwiftUI documents that doesn't use value to initialize are presented on navigationstack without path.

NavigationStack {
    List {
        NavigationLink("Mint") { ColorDetail(color: .mint) }
        NavigationLink("Pink") { ColorDetail(color: .pink) }
        NavigationLink("Teal") { ColorDetail(color: .teal) }
    }
    .navigationTitle("Colors")
}