SwiftUI多行TextField点击Done键无法收起键盘且触发换行问题
解决SwiftUI TextField点击Done按钮换行而非收起键盘的问题
问题根源
设置axis: .vertical后,SwiftUI的TextField会切换为多行输入模式(底层基于UITextView实现),此时系统默认将Done按钮的行为设为插入换行,而非触发提交事件,这直接导致.submitLabel(.done)和.onSubmit完全失效。
解决方案
根据你完全禁止换行、点击Done收起键盘的需求,提供两种可行方案:
方案1:移除垂直轴设置(推荐,无需自定义组件)
如果仅需要内容过长时自动换行,不需要手动输入换行,直接去掉axis: .vertical即可。默认的水平轴TextField会将Done按钮绑定到提交事件:
TextField( "Describe...", text: $text ) .focused(focused, equals: .prompt) .textFieldStyle(.roundedBorder) .lineLimit(2...) // 内容过长时自动换行,禁止手动输入换行 .modifier(ClearButton(text: $text)) .submitLabel(.done) .onSubmit { hideKeyboard() print("test") }
方案2:自定义TextField(强制控制Done行为)
如果必须保留axis: .vertical的特性,需要基于UIKit封装自定义TextField,完全拦截换行输入并控制Done按钮行为:
import SwiftUI import UIKit struct NoNewLineTextField: UIViewRepresentable { let placeholder: String @Binding var text: String let onDone: () -> Void func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.placeholder = placeholder textField.borderStyle = .roundedRect textField.delegate = context.coordinator textField.returnKeyType = .done textField.numberOfLines = 0 textField.lineBreakMode = .byWordWrapping textField.maximumNumberOfLines = 2 return textField } func updateUIView(_ uiView: UITextField, context: Context) { uiView.text = text } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextFieldDelegate { let parent: NoNewLineTextField init(_ parent: NoNewLineTextField) { self.parent = parent } // 拦截换行输入 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if string == "\n" { parent.onDone() return false } let newText = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) ?? "" parent.text = newText.replacingOccurrences(of: "\n", with: "") return true } // Done按钮触发时收起键盘 func textFieldShouldReturn(_ textField: UITextField) -> Bool { parent.onDone() textField.resignFirstResponder() return false } } } // 使用示例 struct ContentView: View { @State private var text = "" @FocusState private var focused: Field? enum Field: Hashable { case prompt } func hideKeyboard() { focused = nil } var body: some View { NoNewLineTextField( placeholder: "Describe...", text: $text, onDone: { hideKeyboard() print("test") } ) .focused(focused, equals: .prompt) .frame(height: 60) } }
内容的提问来源于stack exchange,提问作者erotsppa
相关产品推荐
相关产品推荐

