I would like to respond to keyboard presses in a UITextField
wrapped as UIViewRepresentable
. This is the code for the wrapper view:
import SwiftUI
import UIKit
struct ContentView: View {
@State var text: String = "Hello."
var body: some View {
WrappedUITextField(text: $text)
}
}
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
textField.autocapitalizationType = .none
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
}
self.currentText = oldText.replacingCharacters(in: textRange, with: string)
print("oldText = \"\(oldText)\", new text = \"\(currentText)\"")
self.text.wrappedValue = currentText
return true
}
func textFieldDidChangeSelection(_ textField: UITextField) {
print("textFieldDidChangeSelection")
}
}
Specifically, I want to trigger some action when pressing left/right arrow key when the cursor is at the left/rightmost edge, e.g., "|abc", where "|" is the cursor position, and the user presses left arrow.
None of the UITextFieldDelegate
methods will work here because pressing left/right arrow key when the cursor is already on the left/rightmost edge (respectively) neither changes the text contents (e.g., textFieldDidBeginEditing()
won't be called) nor cursor position (e.g., textFieldDidChangeSelection()
won't be called).
How do I respond to left/right arrow keys in this case? Something like a pressesBegan()
method would be nice here, but I couldn't figure out how to integrate that with UIViewRepresentable
(e.g., adding override func pressesBegan(...)
to Coordinator
doesn't work).
Thanks
Just create your class inherited UITextField
and override handler there
func makeUIView(context: Context) -> UITextField {
let textField = MyTextField() // << here !!
textField.delegate = context.coordinator
textField.text = text
textField.autocapitalizationType = .none
return textField
}
class MyTextField: UITextField {
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
// handle here requried events
// call super if not handled above
super.pressesBegan(presses, with: event)
}
}