SwiftUI键盘ToolbarItem点击后消失的真机适配问题求助
修复SwiftUI键盘ToolbarItem在iOS16.3+真机消失的问题
问题根源
iOS16.3版本的SwiftUI键盘Toolbar存在视图刷新逻辑bug,当通过ToolbarItem触发输入框焦点切换时,系统会错误地销毁并重建键盘Toolbar,导致按钮丢失;而iOS16.2模拟器的Toolbar渲染逻辑尚未引入该问题,因此表现正常。
具体修复方案
1. 用ToolbarItemGroup包裹ToolbarItem(优先推荐)
将单独的ToolbarItem放入ToolbarItemGroup(placement: .keyboard)中,强化系统对键盘Toolbar结构的识别,避免意外销毁:
struct ContentView: View { @FocusState private var focusedField: Field? enum Field { case username, password } var body: some View { Form { TextField("用户名", text: .constant("")) .focused($focusedField, equals: .username) SecureField("密码", text: .constant("")) .focused($focusedField, equals: .password) } .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("下一项") { focusedField = focusedField == .username ? .password : nil } } } } }
2. 优化焦点切换的执行逻辑
如果必须单独使用ToolbarItem,可在焦点切换操作外包裹withAnimation,或加入微延迟,减少视图刷新冲突:
Button("下一项") { withAnimation { focusedField = focusedField == .username ? .password : nil } }
3. 改用UIKit兼容层(终极稳定方案)
若上述SwiftUI原生方案无效,可通过UIKit的inputAccessoryView实现键盘工具栏,彻底规避SwiftUI的版本bug:
struct TextFieldWithToolbar: UIViewRepresentable { var placeholder: String @Binding var text: String var nextAction: () -> Void func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.placeholder = placeholder // 构建键盘工具栏 let toolbar = UIToolbar() toolbar.sizeToFit() let nextButton = UIBarButtonItem(title: "下一项", style: .plain, target: context.coordinator, action: #selector(Coordinator.nextTapped)) toolbar.items = [UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil), nextButton] textField.inputAccessoryView = toolbar return textField } func updateUIView(_ uiView: UITextField, context: Context) { uiView.text = text } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject { var parent: TextFieldWithToolbar init(_ parent: TextFieldWithToolbar) { self.parent = parent } @objc func nextTapped() { parent.nextAction() } } } // 使用示例 struct ContentView: View { @FocusState private var focusedField: Field? @State private var username = "" @State private var password = "" enum Field { case username, password } var body: some View { Form { TextFieldWithToolbar(placeholder: "用户名", text: $username) { focusedField = .password } .focused($focusedField, equals: .username) SecureField("密码", text: $password) .focused($focusedField, equals: .password) } } }
额外注意事项
- 确保
@FocusState变量与输入框的绑定逻辑正确,避免状态混乱引发Toolbar异常 - 尽量简化ToolbarItem的action逻辑,避免在其中执行复杂的视图更新操作
内容的提问来源于stack exchange,提问作者DeveloperSammy
相关产品推荐
相关产品推荐

