简体   繁体   中英

Custom TextField keyboard in SwiftUI with UIViewRepresentable

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM