SwiftUI TextField点击Next切换时键盘反复隐藏显示问题求助
解决SwiftUI TextField切换焦点时键盘闪烁问题
你的问题出在输入框键盘类型不一致:第一个TextField用默认键盘,第二个用numbersAndPunctuation类型键盘,切换时iOS系统会销毁旧键盘并加载新键盘,导致出现闪烁。
方案1:统一键盘类型+输入过滤(最简单)
保持所有输入框使用相同的默认键盘,通过代码过滤第二个输入框的内容,只允许输入数字和标点:
struct CreditEditorScreen: View { enum FocusedField: Hashable { case creditor, amount, purpose } @State private var creditor : String = "" @State private var amount : String = "" @State private var purpose : String = "" @State private var date : Date = Date() @FocusState private var focusedField : FocusedField? var body: some View { NavigationStack { VStack { TextField("creditor", text: $creditor) .focused($focusedField, equals: .creditor) .submitLabel(.next) .onSubmit { focusedField = .amount } // 修改这里:用默认键盘+输入过滤 TextField("amount", text: $amount) .focused($focusedField, equals: .amount) .submitLabel(.next) .onSubmit { focusedField = .purpose } // 过滤输入,只保留数字和小数点,且限制单个小数点 .onChange(of: amount) { newValue in let allowedCharacters = CharacterSet(charactersIn: "0123456789.") let filtered = newValue.unicodeScalars.filter { allowedCharacters.contains($0) }.map(String.init).joined() amount = filtered.components(separatedBy: ".").count > 2 ? String(filtered.dropLast()) : filtered } TextField("purpose", text: $purpose) .focused($focusedField, equals: .purpose) .submitLabel(.done) DatePicker("date", selection: $date, displayedComponents: [.date]) Spacer() Button("Save") { } } .onAppear { focusedField = .creditor } .padding() } } }
方案2:用UIKit包装TextField(无缝切换不同键盘)
如果必须使用不同类型的键盘,可以通过UIKit的UITextField实现无缝切换,避免系统销毁重建键盘:
// 自定义UIKit包装的TextField struct CustomUITextField: UIViewRepresentable { let placeholder: String @Binding var text: String let keyboardType: UIKeyboardType let returnKeyType: UIReturnKeyType var onReturn: () -> Void func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.placeholder = placeholder textField.keyboardType = keyboardType textField.returnKeyType = returnKeyType textField.delegate = context.coordinator textField.autocapitalizationType = .none return textField } func updateUIView(_ uiView: UITextField, context: Context) { if uiView.text != text { uiView.text = text } } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextFieldDelegate { let parent: CustomUITextField init(_ parent: CustomUITextField) { self.parent = parent } func textFieldShouldReturn(_ textField: UITextField) -> Bool { parent.onReturn() return true } } } // 视图中使用自定义TextField struct CreditEditorScreen: View { @State private var creditor: String = "" @State private var amount: String = "" @State private var purpose: String = "" @State private var date: Date = Date() // 用tag标记输入框,方便切换焦点 @State private var activeTag: Int = 0 var body: some View { NavigationStack { VStack { CustomUITextField( placeholder: "creditor", text: $creditor, keyboardType: .default, returnKeyType: .next, onReturn: { activeTag = 1 } ) .tag(0) CustomUITextField( placeholder: "amount", text: $amount, keyboardType: .numbersAndPunctuation, returnKeyType: .next, onReturn: { activeTag = 2 } ) .tag(1) CustomUITextField( placeholder: "purpose", text: $purpose, keyboardType: .default, returnKeyType: .done, onReturn: { activeTag = -1 } ) .tag(2) DatePicker("date", selection: $date, displayedComponents: [.date]) Spacer() Button("Save") { } } .onAppear { // 自动聚焦第一个输入框 DispatchQueue.main.async { UIApplication.shared.sendAction(#selector(UITextField.becomeFirstResponder), to: nil, from: nil, for: nil) } } .padding() // 监听activeTag变化,切换焦点 .onChange(of: activeTag) { tag in if tag >= 0 { DispatchQueue.main.async { let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first keyWindow?.viewWithTag(tag)?.becomeFirstResponder() } } else { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } } } }
说明
- 方案1适合大多数场景,实现简单,避免了键盘类型切换带来的闪烁。
- 方案2适合必须使用不同键盘类型的场景,通过UIKit原生API直接控制焦点,实现无缝切换。
内容的提问来源于stack exchange,提问作者Abdurakhmon
相关产品推荐
相关产品推荐

