DEV Community

Cover image for Adding a "Done" Button to iOS Numpad in Flutter
Dinko Marinac
Dinko Marinac

Posted on • Originally published at dinkomarinac.dev

Adding a "Done" Button to iOS Numpad in Flutter

This week I had to add an “done” action to a numbers only text field. Seems easy.

textInputAction: TextInputAction.done
Enter fullscreen mode Exit fullscreen mode

Done.

Couple of hours later I got a message: “Doesn’t work on iOS”.

I went on Google to search for a solutions. Stack Overflow suggested to change my keyboard type and add an a TextInputFormatter :

textInputAction: TextInputAction.done,
keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true)
inputFormatters: <TextInputFormatter>[
  FilteringTextInputFormatter.digitsOnly,
],
Enter fullscreen mode Exit fullscreen mode

This solution works, but now, the user gets a regular keyboard and can enter anything, which is not the behaviour I am looking for.

I should be able to have only numbers and decimal separators (. , ,) on the keyboard and a done button to finish typing.

After some research, I found the problem → iOS doesn’t support this behaviour. Even native developers have their workarounds.

Thankfully, Flutter has a plugin that can help: KeyboardActions.

You can use this to add any actions above the keyboard. A great example are Slack and Notion which add buttons for styling about the keyboard in their mobile apps.

Here’s how it works.

First you need to define all the actions you want to add to this keyboard.

final FocusNode _focusNode = FocusNode();

KeyboardActionsConfig get _keyboardActionsConfig {
    return KeyboardActionsConfig(
      keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
      keyboardBarColor: const Color(0xFFCAD1D9), //Apple keyboard color
      actions: [
        KeyboardActionsItem(
          focusNode: _focusNode,
          toolbarButtons: [
            (node) {
              return GestureDetector(
                onTap: () => node.unfocus(),
                child: Container(
                  padding: const EdgeInsets.all(12.0),
                  child: Text(
                    S.of(context).done,
                    style: const TextStyle(
                      color: Color(0xFF0978ED), //Done button color
                      fontWeight: FontWeight.bold,
                    ), 
                  ),
                ),
              );
            }
          ],
        ),
      ],
    );
  }
Enter fullscreen mode Exit fullscreen mode

All “Done” button does is unfocusing of the TextField we are currently using, which is where the onTap method implementation comes from. I’m using Apple’s default coloring here, but you could you anything you want.

After that you need to wrap your TextField with the KeyboardActions Widget.

KeyboardActions(
  config: _keyboardActionsConfig,
  disableScroll: true,
  child: TextFormField(
    focusNode: _focusNode, // <-- don't forget to add the focus node
    controller: widget.controller,
    onChanged: (value) {
        final input = double.tryParse(value) ?? 0
        //TODO: do something with the input
    }
    labelText: widget.labelText,
    keyboardType:
        const TextInputType.numberWithOptions(decimal: true),
    textInputAction: TextInputAction.done,
  ),
);
Enter fullscreen mode Exit fullscreen mode

Make sure not to forget adding the focus node to the field, otherwise this will not work.

The end result looks like this:

Custom Done button on iOS numpad in Flutter

That’s it. You made your product manager happy.

If you have found this useful, make sure to like and follow for more content like this. To know when the new articles are coming out, follow me on Twitter and LinkedIn.

Until next time, happy coding!

Top comments (0)