Extend SwiftUI Keyboard with Custom Button Extend SwiftUI Keyboard with Custom Button xcode xcode

Extend SwiftUI Keyboard with Custom Button


Solved the issue using UIRepresentable protocol

struct TestTextfield: UIViewRepresentable {    @Binding var text: String    var keyType: UIKeyboardType    func makeUIView(context: Context) -> UITextField {        let textfield = UITextField()      textfield.keyboardType = keyType        let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textfield.frame.size.width, height: 44))        let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textfield.doneButtonTapped(button:)))        toolBar.items = [doneButton]        toolBar.setItems([doneButton], animated: true)        textfield.inputAccessoryView = toolBar        return textfield    }        func updateUIView(_ uiView: UITextField, context: Context) {        uiView.text = text            }}extension  UITextField{    @objc func doneButtonTapped(button:UIBarButtonItem) -> Void {       self.resignFirstResponder()    }}

Using in content view

struct ContentView : View {    @State var text = ""        var body: some View {        TestTextfield(text: $text, keyType: UIKeyboardType.phonePad)            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50)            .overlay(                RoundedRectangle(cornerRadius: 16)                    .stroke(Color.blue, lineWidth: 4)        )    }}


I did it in 5 lines using the SwiftUI-Introspect library! I had a problem that the Representable Text Field did not react in any way to padding and frame. Everything was decided using this library!

Link: https://github.com/siteline/SwiftUI-Introspect

import SwiftUIimport Introspectstruct ContentView : View {@State var text = ""var body: some View {    TextField("placeHolder", text: $text)       .keyboardType(.default)       .introspectTextField { (textField) in           let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textField.frame.size.width, height: 44))           let flexButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)           let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textField.doneButtonTapped(button:)))           doneButton.tintColor = .systemPink           toolBar.items = [flexButton, doneButton]           toolBar.setItems([flexButton, doneButton], animated: true)           textField.inputAccessoryView = toolBar        }}extension  UITextField {   @objc func doneButtonTapped(button:UIBarButtonItem) -> Void {      self.resignFirstResponder()   }}

output


If there is an issue with @Binding implement the Coordinator class which conforms to the UITextFieldDelegate. This will allow one to be able to customize the TextField further if required.

struct DecimalTextField: 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 doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textfield.doneButtonTapped(button:)))        toolBar.items = [doneButton]        toolBar.setItems([doneButton], animated: true)        textfield.inputAccessoryView = toolBar        return textfield     }     func updateUIView(_ uiView: UITextField, context: Context) {        uiView.text = text     }     func makeCoordinator() -> Coordinator {        Coordinator(self)     }     class Coordinator: NSObject, UITextFieldDelegate {        var parent: DecimalTextField         init(_ textField: DecimalTextField) {        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     }   } }