[英]Setting up .onCommit{} in UITextFieldViewRepresentable SwiftUI
I bridge UIKit with SwiftUI as follows:我将 UIKit 与 SwiftUI 桥接如下:
struct UITextFieldViewRepresentable: UIViewRepresentable {
@Binding var language: String
@Binding var text: String
init(language: Binding<String>, text: Binding<String>) {
self._language = language
self._text = text
}
func makeUIView(context: Context) -> UITextField {
let textField = getTextField()
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
// Change the language in the wordTextField here.
if let wordTextField = uiView as? WordTextField {
wordTextField.language = self.language
}
}
private func getTextField() -> UITextField {
let textField = WordTextField(frame: .zero)
textField.language = self.language
textField.textAlignment = .center
textField.font = UIFont.systemFont(ofSize: 15, weight: .regular)
return textField
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text)
}
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
self._text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
class WordTextField: UITextField {
var language: String? {
didSet {
if self.isFirstResponder{
self.resignFirstResponder()
self.becomeFirstResponder()
}
}
}
override var textInputMode: UITextInputMode? {
if let language = self.language {
print("text input mode: \(language)")
for inputMode in UITextInputMode.activeInputModes {
if let inputModeLanguage = inputMode.primaryLanguage, inputModeLanguage == language {
return inputMode
}
}
}
return super.textInputMode
}
}
}
And call it as follows:并按如下方式调用它:
UITextFieldViewRepresentable(language: $keyboardLanguage, text: $foreignThing)
This works fine in some parts of my app.这在我的应用程序的某些部分工作正常。 In other parts, I need a text field which calls a method when the user taps the enter key after entering text.
在其他部分,我需要一个文本字段,当用户在输入文本后点击回车键时调用一个方法。 It's written like this:
是这样写的:
TextField("", text: Binding<String>(
get: { self.userAnswer },
set: {
self.userAnswer = $0
self.enableHint()
}), onCommit: {
if self.userAnswer.isEmpty {
answerPlaceholder = NSMutableAttributedString(string: "Tap here to answer...")
} else {
answerDisabled = true
checkAnswer()
}
})
I tried implementing the above with UITextFieldViewRepresenatable as follows:我尝试使用 UITextFieldViewRepresenatable 实现上述内容,如下所示:
UITextFieldViewRepresentable(language: $keyboardLanguage, text: Binding<String>(
get: { self.userAnswer },
set: {
self.userAnswer = $0
self.enableHint()
}), onCommit: {
if self.userAnswer.isEmpty {
answerPlaceholder = NSMutableAttributedString(string: "Tap here to answer...")
} else {
answerDisabled = true
checkAnswer()
}
})
I'm getting 'compiler couldn't type check this expression in reasonable time' error.我收到“编译器无法在合理的时间内检查此表达式的类型”错误。 I think I've narrowed it down to not implementing.onCommit:{} in my UITextFieldViewRepresentable()
我想我已经将范围缩小到不在我的 UITextFieldViewRepresentable() 中执行 .onCommit:{}
If this is the problem, then I'd like to know how.onCommit:{} can be implemented in UITextFieldViewRepresentable().如果这是问题所在,那么我想知道如何在 UITextFieldViewRepresentable() 中实现 onCommit:{}。
There are a few mistakes in the UIViewRepresentable implementation: UIViewRepresentable 实现中有一些错误:
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text)
}
This text binding will be out of date when the View is recreated, so change it to:重新创建视图时,此文本绑定将过时,因此将其更改为:
func makeCoordinator() -> Coordinator {
return Coordinator()
}
You can store the textField inside the coordinator, make it a lazy, set delegate self, then return it from the make func, eg..您可以将 textField 存储在协调器中,使其成为惰性的,设置委托自我,然后从 make func 返回它,例如..
func makeUIView(context: Context) -> UITextField {
context.coordinator.textField // lazy property that sets delegate self.
}
In update, you need to make use of the new value of the binding, eg在更新中,您需要使用绑定的新值,例如
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
// Change the language in the wordTextField here.
if let wordTextField = uiView as? WordTextField {
wordTextField.language = self.language
}
// use the new binding
context.coordinator.textDidChange = { newText in
text = newText
}
}
class Coordinator: NSObject, UITextFieldDelegate {
lazy var textField: UITextField = {
let textField = UITextField()
textField.delegate = self
return textField
}()
var textDidChange: ((String) -> Void)?
func textFieldDidChangeSelection(_ textField: UITextField) {
textDidChange?(textField.text)
}
}
You'll see something similar in PaymentButton.swift in Apple's Fruta sample .您会在 Apple 的Fruta 示例中的 PaymentButton.swift 中看到类似的内容。
Perhaps a simpler way would be this (but I've not tested it yet):也许更简单的方法是这样(但我还没有测试过):
// update
context.coordinator.textBinding = _text
// Coordinator
var textBinding: Binding<String>?
// textViewDidChange
textBinding?.wrappedValue = textField.text
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.