SwiftUI中如何通过navigationDestination传递FocusState?
问题分析与解决方案
跨导航视图传递父视图的FocusState绑定无法正常关闭键盘,核心原因是**FocusState的作用域绑定到原视图的视图层级**,导航后的新视图属于独立的导航栈层级,导致状态变更无法正确同步到新视图的TextField。
以下是两种可行的解决方式:
方案1:让目标视图独立管理FocusState
这是最符合SwiftUI状态管理规范的做法,每个视图负责自身的焦点状态:
修改View_2代码,自行声明并管理FocusState:
struct View_2: View { @ObservedObject var viewModel: View_1.ViewModel @FocusState private var localFocus: View_1.ViewModel.Field? // 本地焦点状态 var body: some View { VStack { TextField("", $viewModel.name) .focused($localFocus, equals: .myTextField) // 绑定本地状态 .toolbar { ToolbarItemGroup(placement: .keyboard) { Button { localFocus = nil // 直接关闭本地焦点 } label: { Image(systemName: "keyboard") } } } } .onAppear { localFocus = .myTextField // 进入视图自动唤起键盘 } } }
View_1中无需传递FocusState绑定,直接初始化View_2即可:
.navigationDestination(for: MyViews) { navigation in if navigation == MyViews.secondView { View_2(viewModel: viewModel) } }
方案2:通过ViewModel传递焦点控制信号
如果需要在父视图和子视图间同步焦点状态,可以在ViewModel中添加信号属性,触发焦点变更:
首先更新ViewModel:
extension View_1 { @MainActor class ViewModel: ObservableObject { @Published var name: String = "" @Published var shouldResignFocus = false // 新增焦点控制信号 enum Field: Hashable { case myTextField } } }
然后在View_2中监听信号,控制本地焦点:
struct View_2: View { @ObservedObject var viewModel: View_1.ViewModel @FocusState private var localFocus: View_1.ViewModel.Field? var body: some View { VStack { TextField("", $viewModel.name) .focused($localFocus, equals: .myTextField) .toolbar { ToolbarItemGroup(placement: .keyboard) { Button { viewModel.shouldResignFocus = true // 触发关闭信号 } label: { Image(systemName: "keyboard") } } } } .onAppear { localFocus = .myTextField } .onChange(of: viewModel.shouldResignFocus) { newValue in if newValue { localFocus = nil viewModel.shouldResignFocus = false // 重置信号 } } } }
这种方式下,父视图也可以通过修改viewModel.shouldResignFocus = true来远程关闭View_2的键盘。
内容的提问来源于stack exchange,提问作者kittonian
相关产品推荐
相关产品推荐

