micah
micah

Reputation: 1248

SwiftUI NavigationStack pop to root

How can I pop to root in the new NavigationStack in IOS 16 while using many NavigationLink's inside other NavigationLink?

Here is a solution for using the NavigationLink(_ title, value: ), but once I try to build out Views with more NavigationLink's inside the .navigationDestination the NavigationStack gives the error A navigationDestination for MyApp.DataObject was declared earlier on the stack. Only the destination declared closest to the root view of the stack will be used.

struct DataObject: Identifiable, Hashable {
    let id = UUID()
    let name: String
}

@available(iOS 16.0, *)
struct ContentView8: View {
    @State private var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path) {
            Text("Root Pop")
                .font(.largeTitle)
                .foregroundColor(.primary)
            
            NavigationLink("Click Item", value: DataObject.init(name: "Item"))
            
            .listStyle(.plain)
            .navigationDestination(for: DataObject.self) { course in
                Text(course.name)
                NavigationLink("Go Deeper", value: DataObject.init(name: "Item"))
                Button("Back to root") {
                    path = NavigationPath()
                }
            }
        }
        .padding()
    }
}

Here is an example of the error from attempting the above approach. Adding the View within the NavigationLink that has another NavigationLink seems to give the error.

struct NavObj: Identifiable, Hashable {
    let id = UUID()
    let name: String
}

@available(iOS 16.0, *)
struct ContentView881: View {
    @State private var path = NavigationPath()
    var body: some View {
        NavigationStack() {
            NavigationLink(destination: T0121(test: 1), label: {Text("Click")})
        }
    }
}

@available(iOS 16.0, *)
struct T0121: View{
    @State var test: Int
    var body: some View{
        VStack{
            Text(String(test))
            NavigationLink(value: NavObj.init(name: "Next"), label: {Text("Click")})
            .navigationDestination(for: NavObj.self) { item in
                T0121(test: 2)
            }
        }
    }
}

Since I have many views within other views I assume I should stick with NavigationLink(destination, label), but the following logic to pop to root which works for NavigationView does not work on the NavigationStack:

@available(iOS 16.0, *)
struct ContentView: View {
    @State private var isActive = false
    var body: some View {
        NavigationStack{
            NavigationLink(destination: TestView(test: 1, isActive: $isActive), isActive: $isActive, label: {Text("Click")})
        }
    }
}

@available(iOS 16.0, *)
struct TestView: View{
    @State var test: Int
    @Binding var isActive: Bool
    var body: some View{
        VStack{
            Text(String(test))
            NavigationLink(destination: TestView(test: test+1, isActive: $isActive), label: {Text("Click")})
            Button(action: {
                isActive = false
            }, label: {
                Text("Root")
            })
        }
    }
}

I apologize for making such a long question, I just wanted to make the issue very clear with plenty of examples. Thank you for any help!!!

Upvotes: 3

Views: 1791

Answers (1)

Ashley Mills
Ashley Mills

Reputation: 53181

The correct way to handle pop-to-root in iOS 16, is to use a NavigationStack with a path, The problem seems to be that the navigationDestination modifier in your example is applied to the NavigationLink itself, it should be applied to the view at the top of the stack that contains the NavigationLink (e.g. List).

So you can fix your second example:

struct NavObj: Identifiable, Hashable {
    let id = UUID()
    let name: String
}

struct ContentView881: View {
    @State private var path = NavigationPath()
    var body: some View {
        NavigationStack() {
            VStack {
                NavigationLink(destination: T0121(test: 1), label: {Text("Click")})

            }
            .navigationDestination(for: NavObj.self) { item in
                T0121(test: 2)
            }
        }
    }
}

struct T0121: View{
    @State var test: Int
    var body: some View{
        VStack{
            Text(String(test))
            NavigationLink(value: NavObj.init(name: "Next"), label: {Text("Click")})
        }
    }
}

Upvotes: 1

Related Questions