I'm using a custom UITextField inside a UIViewRepresentable, to have a Textfield with only a decimalpad and a custom keyboard toolbar. The goal is to add to the toolbar basic things such as inserting a minus, an E, etc... I've seen a lot of code that only adresses the "Done" button. I've tried adding insertText() to the button action but I think the Coordinator is not called and therefore the text is not updated. All I want is the ability of inserting a custom string on the cursor position.
Here is the code:
struct DataTextField: UIViewRepresentable {
private var placeholder: String
@Binding var text: String
init(_ placeholder: String, text: Binding<String>) {
self.placeholder = placeholder
self._text = text
}
func makeUIView(context: Context) -> UITextField {
let textfield = UITextField()
textfield.keyboardType = .decimalPad
textfield.delegate = context.coordinator
textfield.placeholder = placeholder
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textfield.frame.size.width, height: 44))
let minusButton = UIBarButtonItem(title: "-", style: .plain, target: self, action: #selector(textfield.minusButtonTapped(button:)))
let scientificButton = UIBarButtonItem(title: "E", style: .plain, target: self, action: #selector(textfield.scientificButtonTapped(button:)))
toolBar.items = [minusButton, scientificButton]
toolBar.setItems([minusButton, scientificButton], animated: true)
textfield.inputAccessoryView = toolBar
textfield.borderStyle = .roundedRect
textfield.textAlignment = .right
textfield.adjustsFontSizeToFitWidth = true
return textfield
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: DataTextField
init(_ textField: DataTextField) {
self.parent = textField
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentValue = textField.text as NSString? {
let proposedValue = currentValue.replacingCharacters(in: range, with: string) as String
self.parent.text = proposedValue
}
return true
}
}
}
extension UITextField {
@objc func minusButtonTapped(button:UIBarButtonItem) -> Void {
insertText("-")
}
@objc func scientificButtonTapped(button:UIBarButtonItem) -> Void {
insertText("E")
}
}
And a video of the problem:
I discovered that it is a Swift bug that only updates the text if its not inside an array. (In my case, it was) After hours trying, I discovered that calling delegate?.textFieldDidBeginEditing?(self)
and then updating the text inside that function makes the buttons work as expected.
extension UITextField {
@objc func minusButtonTapped(button: UIBarButtonItem) -> Void {
insertText("-")
delegate?.textFieldDidBeginEditing?(self)
}
@objc func scientificButtonTapped(button: UIBarButtonItem) -> Void {
insertText("E")
delegate?.textFieldDidBeginEditing?(self)
}
}
Add this to the Coordinator class inside the UIViewRepresentable:
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
textField.resignFirstResponder()
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.parent.text = textField.text!
}
Calling .resignFirstResponder()
is a must. The app will crash if the keyboard is not dismissed, since in my case the view itself can be dismissed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.