This week I had to add an “done” action to a numbers only text field. Seems easy.
textInputAction: TextInputAction.done
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,
],
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,
),
),
),
);
}
],
),
],
);
}
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,
),
);
Make sure not to forget adding the focus node to the field, otherwise this will not work.
The end result looks like this:
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)