Darren Oakey
Darren Oakey

Reputation: 3654

swift ui extension to textfield for done button

I have an iOS app with several numeric textfield fields using .keyboardType( .decimalPad) - but there's no way of sort of saying "yep" I'm done with editing now - so I want some sort of done or accept on the keyboard

When I search for that - I find heaps of examples, but they are mostly to do with UITextfield, not textfield - and set something called InputAccessoryView - which textfield apparently doesn't support. When I search filter them out - I find all sorts of strange wrappers and things that do things like add toolbars in the parent component, not the text field itself - and I have lots of text fields on lots of pages, so really want to solve it at the textfield level.

What I want is to build an extension to textfield - such that I can add a done button to dismiss it - ie this code here, but something that actually compiles - because the last line doesn't work:

extension TextField {
    func addDoneButtonOnKeyboard() {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default

        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: nil)

        let items = [flexSpace, done]
        doneToolbar.items = items
        doneToolbar.sizeToFit()

        self.inputAccessoryView = doneToolbar
    }
}

so I can just say in my swiftui code:

     TextField("blah", $blah).addDoneButtonOnKeyboard()

also - I have had suggestions pointing me to other questions that do things like wrap a UITextField in UIRepresentable - to sort of access UIKit in swift... but I really want to arrive at a solution which is an extension on "TextField", and apart from the suggestion of using a 3rd party library, "introspect" - all the other suggestions end up creating a new class.

Upvotes: 0

Views: 2113

Answers (1)

Darren Oakey
Darren Oakey

Reputation: 3654

for anyone interested - I couldn't find anyway around introspect (one day I'll look at what it's doing and pull out the key parts) - but it did give me a solution - so with this extension:

public extension TextField
{
    func addDoneButtonOnKeyboard() -> some View
    {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        doneToolbar.barStyle = .default
        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: nil, action: nil)
        doneToolbar.items = [flexSpace, done]
        doneToolbar.sizeToFit()
        return self.introspectTextField
        {
            text_field in
            text_field.inputAccessoryView = doneToolbar
            done.target = text_field
            done.action = #selector( text_field.resignFirstResponder )
        }
    }
}

all you have to do is add .addDoneButtonOnKeyboard() to your textfield in the view.

Upvotes: -2

Related Questions