如何在新的 NavigationStack.navigationDestination 中将绑定传递给子视图

P. *_*tas 21 swift swiftui

我正在尝试将绑定从父列表视图传递到子详细视图。子级详细信息视图包含编辑子级的逻辑。我希望这些更改反映在父列表视图中:

import SwiftUI

struct ParentListView: View {
    var body: some View {
        NavigationStack {
            List {
                ForEach(0 ..< 5) { number in
                    NavigationLink(value: number) {
                        Text("\(number)")
                    }
                }
            }
            .navigationDestination(for: Int.self) { number in
                ChildDetailView(number: number) //Cannot convert value of type 'Int' to expected argument type 'Binding<Int>'

            }
        }
    }
}

struct ChildDetailView: View {
    @Binding var number: Int
    var body: some View {
        VStack {
            Text("\(number)")
            Button {
                number += 10
            } label: {
                Text("Add 10")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,我无法将数字传递到 ChildDetailView 中,因为它需要绑定。我尝试过在数字前加上 $,但这也不起作用。有没有办法做到这一点,或者我使用新的 NavigationStack 完全错误吗?

Asp*_*eri 12

好吧,实际上这是可能的,但首先需要事实来源,即具有要绑定的数据的状态,但在这种情况下,绑定将仅更新源,而不更新目的地。在这种情况下使用ObservableObject视图模型更合适。

使用 Xcode 14 / iOS 16 进行测试

注意:在这种情况下绑定不会刷新ChildDetailView- in 只能用于操作,但源已更新!

这是主要部分:

@State private var numbers = [1, 2, 3, 4, 5]  // << data !!
var body: some View {
    NavigationStack {
        List {
            ForEach($numbers) { number in      // << binding !!
                NavigationLink(value: number) {
                    Text("\(number.wrappedValue)")
                }
            }
        }
        .navigationDestination(for: Binding<Int>.self) { number in // << !!
            ChildDetailView(number: number)  // << binding !!
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

绑定需要一些扩展来通过导航链接值进行传输。

GitHub 上的完整代码


thi*_*ezn 10

Apple 的 Foodtruck 示例应用程序提供了一个有关如何处理 navigationDestination 中的绑定的示例。看看他们的 github 存储库中的以下行

        .navigationDestination(for: Donut.ID.self) { donutID in
            DonutEditor(donut: model.donutBinding(id: donutID))
        }
Run Code Online (Sandbox Code Playgroud)

他们使用 Donut 模型 ID 进行导航。为了传递绑定,他们在 FoodTruck 模型上添加了一个 getter/setter,其中包含一个甜甜圈列表,以通过 Donut.ID 生成绑定。

    public func donutBinding(id: Donut.ID) -> Binding<Donut> {
        Binding<Donut> {
            self.donuts[id]
        } set: { newValue in
            self.donuts[id] = newValue
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这实际上可以通过美元语法来完成,我很惊讶为 Food Truck 的这一部分编写代码的人不知道:DonutEditor(donut: $model.donuts[donutID])。无论如何,详细地使用 @Binding 时,主体发生更改时不会被调用,因此 Apple 必须在未来的测试版中修复此问题。 (2认同)