我正在使用包装在UIViewRepresentable中的UITextField,因此可以在SwiftUI中使用它。我从几个SO答案中总结了这一点。
struct RADTextField: UIViewRepresentable {
@ObservedObject var dataVM: DataVM
var placeholder: String
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<RADTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
textField.delegate = context.coordinator
textField.clearButtonMode = .whileEditing
textField.returnKeyType = .done
textField.placeholder = self.placeholder
textField.adjustsFontForContentSizeCategory = true
return textField
}
func makeCoordinator() -> RADTextField.Coordinator {
return Coordinator(dataVM: self.dataVM)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<RADTextField>) {
uiView.text = dataVM.fieldOne
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
协调员:
extension RADTextField {
class Coordinator: NSObject, UITextFieldDelegate {
@ObservedObject var dataVM : DataVM
var didBecomeFirstResponder = false
init(dataVM: DataVM) {
self.dataVM = dataVM
}
func textFieldDidChangeSelection(_ textField: UITextField) {
self.dataVM.fieldOne = textField.text ?? ""
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Update Cursor
let positionOriginal = textField.beginningOfDocument
let cursorLocation = textField.position(from: positionOriginal, offset: (range.location + string.count))
if let txt = textField.text {
textField.text = NSString(string: txt).replacingCharacters(in: range, with: string)
}
// ✳️ I think this is where the issue is ✳️
if let cursorLocation = cursorLocation {
textField.selectedTextRange = textField.textRange(from: cursorLocation, to: cursorLocation)
}
return false
}
}
}
问题是,当我尝试将光标手动放置在文本中的某个位置并键入表情符号时,我键入的下一个字符将“分割”表情符号。我认为某些表情符号字符实际上是两个字符,但是我不知道该如何处理。我用the️标记了代码,指出了我认为问题出在哪里。
答案 0 :(得分:0)
如果 UITextField 文本没有在每次输入字符时使用模型中的值进行不必要的更新,则可以避免设置光标位置的需要。
这可以通过将 textField 回调方法中接收到的当前文本存储在 Coordinator 的一个属性中来实现。在 updateUIView 方法中,此属性用于与模型值进行比较。
这是一个简化的例子:
struct WrappedUITextField: UIViewRepresentable {
@Binding var text: String
func makeCoordinator() -> Coordinator {
Coordinator($text)
}
func makeUIView(context: Context) -> UITextField {
let textField = UITextField()
textField.delegate = context.coordinator
textField.text = text
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
if text != context.coordinator.currentText {
uiView.text = text
}
}
}
class Coordinator: NSObject, UITextFieldDelegate {
var text: Binding<String>
var currentText: String
init(_ text: Binding<String>) {
self.text = text
currentText = text.wrappedValue
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let oldText = textField.text, let textRange = Range(range, in: oldText) else {
return false
}
currentText = oldText.replacingCharacters(in: textRange, with: string)
text.wrappedValue = currentText
return true
}
}
工作的双向绑定可以测试如下:
struct ContentView: View {
@State var text = "example"
var body: some View {
WrappedUITextField(text: $text)
WrappedUITextField(text: $text)
}
}