如何从导航树return到起始视图?

How to return to the starting view from the navigation tree?

假设我有一个数组,我首先在另一个视图中追加一个元素,然后在第三个视图中追加第二个元素。如何return到起始视图并从内存中推断出两个额外的视图?

    struct ContentView: View {
    @State var array: [String] = []
    
    var body: some View {
        NavigationView{
            ScrollView{
                ForEach(array, id: \.self) { element in
                    Text(element)
                }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    NavigationLink("+") {
                        Details(array: $array)
                    }
                }
            }
        }
    }
}

struct Details: View {
    @Binding var array: [String]
    var body: some View {
        Button(action: { array.append("First Element") }) {
            Text("Append First Element")
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                NavigationLink("+") {
                }
            }
        }
    }
}

struct MoreDetails: View {
    @Binding var array: [String]
    @Environment(\.dismiss) var dismiss

    var body: some View {
        Button(action: { array.append("Second Element") }) {
            Text("Append Second Element")
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                NavigationLink("Done") {
                    ContentView(array: array)
                }
                .simultaneousGesture(TapGesture().onEnded{
                    dismiss()
                })
            }
        }
    }
}

您真正遇到的问题是导航问题,或者至少是您认为自己想要导航的方式。你设置的导航是这样的:

Original ContentView -> Details -> MoreDetails -> New ContentView

当你想要的是:

Original ContentView -> Details -> MoreDetails -> Original ContentView

无需返回浏览所有视图。要做到这一点,基本上就是搭建一个纸牌屋,然后将底部的卡片拉出,然后您的导航会折叠回原来的状态 ContentView。注释代码:

struct ContentView: View {
    @State var array: [String] = []
    // originalIsActive is your bottom card, and you will carry a reference
    // through your views like a piece of twine.
    @State var originalIsActive = false
    
    var body: some View {
        NavigationView{
            ScrollView{
                ForEach(array, id: \.self) { element in
                    Text(element)
                }
            }
            .background(
                // This is a programatic NavigationLink that triggers when originalIsActive
                // becomes true. Placed in a background it sits and listens for originalIsActive.
                NavigationLink(isActive: $originalIsActive, destination: {
                    Details(array: $array, originalIsActive: $originalIsActive)
                }, label: {
                    // This is simply a nothing view, so you can't see the NavigationLink.
                    EmptyView()
                })
                // Necessary to prevent link pop back after this NavigationLink
                .isDetailLink(false)
            )
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        // This Button sets originalIsActive to true, activating the NavigationLink.
                        originalIsActive = true
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
    }
}

struct Details: View {
    @Binding var array: [String]
    // Reference to originalIsActive
    @Binding var originalIsActive: Bool
    
    @State var detailsIsActive = false
    
    var body: some View {
        Button(action: { array.append("First Element") }) {
            Text("Append First Element")
        }
        .background(
            NavigationLink(isActive: $detailsIsActive, destination: {
                MoreDetails(array: $array, originalIsActive: $originalIsActive)
            }, label: {
                EmptyView()
            })
            // Necessary to prevent link pop back after this NavigationLink
            .isDetailLink(false)
        )
        .toolbar {
            Button {
                detailsIsActive = true
            } label: {
                Image(systemName: "plus")
            }
        }
    }
}

struct MoreDetails: View {
    @Binding var array: [String]
    // Reference to originalIsActive
    @Binding var originalIsActive: Bool

    var body: some View {
        Button(action: { array.append("Second Element") }) {
            Text("Append Second Element")
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button {
                    // By setting originalIsActive to false, you pull out the bottom card.
                    // If the first link does not exist, none do.
                    originalIsActive = false
                } label: {
                    Text("Original")
                }

            }
        }
    }
}