You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 06:35:10