SwiftUI问题:非根视图中TextField的键盘工具栏不显示
问题现象
- 在运行iOS 18.2的iPhone 12 Pro设备上,根视图使用
NavigationStack,推送包含TextField的子视图后,TextField获得焦点时,带Done按钮的键盘工具栏无法显示。 - 将该
TextField直接放在根视图中,键盘工具栏可正常显示。 - iOS 18模拟器无此异常。
代码重现
struct HomeView: View { @State private var navigationDestinationIsPresented = false var body: some View { NavigationStack { Button("Push Me") { self.navigationDestinationIsPresented = true } .buttonStyle(.borderedProminent) .navigationDestination(isPresented: self.$navigationDestinationIsPresented) { NextView() } } } } struct NextView: View { var body: some View { NumTextField() } } struct NumTextField: View { @State private var userInput: String = "" @FocusState var isFocused: Bool var body: some View { TextField("", text: self.$userInput) .border(Color.black, width: 1.0) .frame(width: 45) .multilineTextAlignment(.center) #if os(iOS) .keyboardType(.numberPad) .toolbar { if (self.isFocused) { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { self.isFocused = false } } } } #endif .focused(self.$isFocused) } }
解决方案
方案1:用toolbar(_:for:)控制显隐,避免条件渲染Toolbar内容
iOS 18.2中,推送子视图的层级下,基于FocusState的条件渲染可能导致Toolbar无法被导航上下文正确识别。改为始终声明Toolbar内容,用toolbar(_:for:)控制键盘工具栏的显隐:
struct NumTextField: View { @State private var userInput: String = "" @FocusState var isFocused: Bool var body: some View { TextField("", text: $userInput) .border(Color.black, width: 1.0) .frame(width: 45) .multilineTextAlignment(.center) #if os(iOS) .keyboardType(.numberPad) // 始终声明Toolbar内容 .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFocused = false } } } // 根据焦点状态控制键盘工具栏的显隐 .toolbar(isFocused ? .visible : .hidden, for: .keyboard) #endif .focused($isFocused) } }
方案2:将Toolbar提升到子视图根层级
把Toolbar附加到推送的子视图(NextView)上,而非TextField的修饰符中,确保导航上下文能正确识别Toolbar:
struct NextView: View { @FocusState private var isFocused: Bool var body: some View { NumTextField(isFocused: $isFocused) .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFocused = false } } } } } struct NumTextField: View { @State private var userInput: String = "" @Binding var isFocused: Bool var body: some View { TextField("", text: $userInput) .border(Color.black, width: 1.0) .frame(width: 45) .multilineTextAlignment(.center) #if os(iOS) .keyboardType(.numberPad) #endif .focused($isFocused) } }
原因分析
该问题大概率是iOS 18.2中NavigationStack推送子视图时,焦点状态更新与Toolbar视图渲染的同步bug。原代码仅在isFocused为true时渲染Toolbar,导致视图层级变化时导航上下文未及时注册Toolbar;模拟器因环境差异未触发该bug。
内容的提问来源于stack exchange,提问作者Ser Pounce
相关产品推荐
相关产品推荐

