我为SwiftUI创建了一个UIViewRepresentable
来包装UITextField
,因此我可以例如当用户敲击Enter键时,更改第一响应者。
这是我的UIViewRepresentable(为了简化起见,我删除了第一个响应程序代码)
struct CustomUIKitTextField: UIViewRepresentable {
@Binding var text: String
var placeholder: String
func makeUIView(context: UIViewRepresentableContext<CustomUIKitTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUIKitTextField>) {
uiView.text = text
uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
uiView.setContentCompressionResistancePriority(.required, for: .vertical)
}
func makeCoordinator() -> CustomUIKitTextField.Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: CustomUIKitTextField
init(parent: CustomUIKitTextField) {
self.parent = parent
}
func textFieldDidChangeSelection(_ textField: UITextField) {
parent.text = textField.text ?? ""
}
}
}
应用程序的第一个屏幕上有一个“通过电子邮件登录”按钮,该按钮可推动MailView显示CustomUIKitTextField
,并将ObservableObject
视图模型的@Published属性用作TextField的文本。
struct MailView: View {
@ObservedObject var viewModel: MailSignUpViewModel
var body: some View {
VStack {
CustomUIKitTextField(placeholder: self.viewModel.placeholder,
text: self.$viewModel.mailAddress)
.padding(.top, 30)
.padding(.bottom, 10)
NavigationLink(destination: UsernameView(viewModel: UsernameSignUpViewModel())) {
Text("Next")
}
Spacer()
}
}
}
一切正常,直到我推送另一个视图,例如MailView,例如用户名视图。它的实现方式完全相同,但是一旦完成键入,CustomUIKitTextField
就会以空字符串以某种方式获得updateUIView
调用。
还有其他怪异的行为,例如当我将MailView和UsernameView包装在另一个NavigationView中时,一切正常。但这显然不是解决问题的方法,因为那时我将拥有多个NavigationViews。
当在视图模型中使用@State属性而不是@Published属性时,它也适用。但是我不想使用@State,因为我真的想将模型代码保留在视图之外。
有人遇到相同或相似的问题吗?
答案 0 :(得分:0)
您似乎使用了错误的委托方法。 textFieldDidChangeSelection
会产生一些不一致的结果(听起来就像您在处理)。相反,我建议您使用textFieldDidEndEditing
,它也可以使您访问传入的控件,但它可以确保在对象离开第一响应者时得到该对象。这很重要,因为这意味着更改属性并释放响应者对象后,您将获得对象。
因此,我将如下更改您的委托方法:
func textFieldDidEndEditing(_ textField: UITextField) {
parent.text = textField.text ?? ""
}
有关更多信息,请参见textFieldDidEndEditing
方法的以下链接:
https://developer.apple.com/documentation/uikit/uitextfielddelegate/1619591-textfielddidendediting
以下是有关UITextFieldDelegate
对象的信息的链接:
https://developer.apple.com/documentation/uikit/uitextfielddelegate
编辑
基于注释,如果您希望每次更改一个字符时都要检查该文本,则应实现此委托函数:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// User pressed the delete key
if string.isEmpty {
// If you want to update your query string here after the delete key is pressed, you can rebuild it like we are below
return true
}
//this will build the full string the user intends so we can use it to build our search
let currentText = textField.text ?? ""
let replacementText = (currentText as NSString).replacingCharacters(in: range, with: string)
// You can set your parent.text here if you like, or you can fire the search function as well
// When you're done though, return true to indicate that the textField should display the changes from the user
return true
}