SwiftUI中如何通过NavigationStack枚举传递Binding?
问题解答
核心结论
不能将Binding传入路由枚举,因为Binding未遵循Hashable协议,而NavigationStack要求路由类型必须实现Hashable(用于管理NavigationPath中的路由记录),直接在枚举关联值中使用Binding会导致编译错误。
替代解决方案
方案1:直接在导航目标中传递Binding
简化路由枚举,不在枚举中携带参数,而是在navigationDestination闭包中直接将父视图的Binding传递给目标视图:
@available(iOS 16.0, *) enum Route: Hashable { case gotoBView } @available(iOS 16.0, *) struct ContentView25: View { @State var input = "Hello" @State var path: NavigationPath = .init() var body: some View { NavigationStack(path: $path){ NavigationLink(value: Route.gotoBView, label: {Text("Go To B")}) .navigationDestination(for: Route.self){ route in switch route { case .gotoBView: BView1(bvar: $input) } } } } } @available(iOS 16.0, *) struct BView1: View { @Binding var bvar: String var body: some View { Text(bvar) Button("修改文本") { bvar = "已更新" } } }
方案2:使用ObservableObject共享状态
如果需要跨多个视图共享状态,将数据封装到ObservableObject中,通过环境传递给目标视图,路由枚举无需携带参数:
class DataStore: ObservableObject { @Published var input = "Hello" } @available(iOS 16.0, *) enum Route: Hashable { case gotoBView } @available(iOS 16.0, *) struct ContentView25: View { @StateObject private var store = DataStore() @State var path: NavigationPath = .init() var body: some View { NavigationStack(path: $path){ NavigationLink(value: Route.gotoBView, label: {Text("Go To B")}) .navigationDestination(for: Route.self){ route in BView1() } .environmentObject(store) } } } @available(iOS 16.0, *) struct BView1: View { @EnvironmentObject var store: DataStore var body: some View { Text(store.input) Button("修改文本") { store.input = "已更新" } } }
方案3:传递初始值+回调更新
如果需要路由携带初始数据,可传递值本身,目标视图通过闭包回调将修改后的数据同步回父视图:
@available(iOS 16.0, *) enum Route: Hashable { case gotoBView(initialValue: String) } @available(iOS 16.0, *) struct ContentView25: View { @State var input = "Hello" @State var path: NavigationPath = .init() var body: some View { NavigationStack(path: $path){ NavigationLink(value: Route.gotoBView(initialValue: input), label: {Text("Go To B")}) .navigationDestination(for: Route.self){ route in switch route { case .gotoBView(let initialValue): BView1(currentValue: initialValue, onUpdate: { newValue in input = newValue }) } } } } } @available(iOS 16.0, *) struct BView1: View { @State private var currentValue: String let onUpdate: (String) -> Void init(currentValue: String, onUpdate: @escaping (String) -> Void) { self._currentValue = State(initialValue: currentValue) self.onUpdate = onUpdate } var body: some View { TextField("编辑文本", text: $currentValue) .onChange(of: currentValue) { newValue in onUpdate(newValue) } } }
推荐方案
优先选择方案1或方案2,这两种方案更符合SwiftUI的状态管理设计思想,避免将依赖上下文的Binding类型耦合到路由枚举中。
内容的提问来源于stack exchange,提问作者micah
相关产品推荐
相关产品推荐

