我有 SwiftUI View,其中有两个普通的 TextField 和一个 UIViewRepresentable UITextField。
我需要在键入值时关闭 UIViewRepresentable 上复制/粘贴/选择的可能性。
我通过在 CustomUITextField 结构(即 UIViewRepresentable UITextField)的协调器上调用的 textFieldShouldBeginEditing 函数下将 false 值设置为 isUserInteractionEnabled 来实现这一点。
问题是,如果我在某些 SwiftUI TextFields 上按回车键,则 textFieldShouldBeginEditing 会触发并将我的 CustomUITextField 设置为不可编辑,然后它才会处于活动状态,因此 CustomUITextField 变得不可触摸,因此我无法键入任何值。
这是 MRE
import SwiftUI
struct ContentView: View {
@State private var name: String = ""
@State private var phone: String = ""
@State private var isFirstResponder = false
var body: some View {
VStack {
Spacer()
HStack {
Text("A")
TextField("", text: $name)
.border(Color.gray.opacity(0.3))
}
HStack {
Text("B")
CustomUITextField(isFirstResponder: $isFirstResponder, text: $phone)
.frame(height: 22)
.border(Color.gray.opacity(0.3))
}
Spacer()
}
.padding()
}
}
#Preview {
ContentView()
}
struct CustomUITextField: UIViewRepresentable {
@Binding var isFirstResponder: Bool
@Binding var text: String
init(isFirstResponder: Binding<Bool>, text: Binding<String>) {
self._isFirstResponder = isFirstResponder
self._text = text
}
func makeUIView(context: UIViewRepresentableContext<CustomUITextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.text = text
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUITextField>) {
context.coordinator.listenToChanges = false
if isFirstResponder != uiView.isFirstResponder {
if isFirstResponder {
uiView.becomeFirstResponder()
} else {
uiView.resignFirstResponder()
}
}
uiView.text = text
context.coordinator.listenToChanges = true
}
func makeCoordinator() -> Coordinator {
let coordinator = Coordinator(isFirstResponder: $isFirstResponder, text: $text)
return coordinator
}
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var isFirstResponder: Bool
@Binding var text: String
fileprivate var listenToChanges: Bool = false
init(isFirstResponder: Binding<Bool>, text: Binding<String>) {
self._isFirstResponder = isFirstResponder
self._text = text
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = false
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = true
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
guard listenToChanges else { return }
isFirstResponder = textField.isFirstResponder
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard listenToChanges else { return }
isFirstResponder = textField.isFirstResponder
text = textField.text ?? ""
}
}
}
如果您在文本字段 A 上输入某些值并按回车键,则无法激活文本字段 B。
当我点击 TextField A 在 textFieldShouldBeginEditing 中进行一些 if 语句时,我尝试通过绑定到 UIViewRepresentable 协调器来传递布尔值,但该函数在 A 字段上的 .onSubmit 事件之前触发。
对于解决这个问题有什么想法吗?
提前致谢
不要像这样使用
textFieldShouldBeginEditing
,您应该做类似于这个答案的事情,即覆盖canPerformAction
以返回 false。
struct CustomUITextField: UIViewRepresentable {
@Binding var text: String
class Wrapper: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
false
}
}
init(text: Binding<String>) {
self._text = text
}
func makeUIView(context: UIViewRepresentableContext<CustomUITextField>) -> UITextField {
let textField = Wrapper(frame: .zero)
textField.textContentType = UITextContentType(rawValue: "")
textField.text = text
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUITextField>) {
context.coordinator.textCallback = { text = $0 }
uiView.text = text
}
func makeCoordinator() -> Coordinator {
.init()
}
class Coordinator: NSObject, UITextFieldDelegate {
var textCallback: ((String) -> Void)?
func textFieldDidEndEditing(_ textField: UITextField) {
textCallback?(textField.text ?? "")
}
}
}
你永远不知道
textFieldShouldBeginEditing
何时被调用,因此在其中添加任何副作用通常是一个坏主意。