Flutter Tips #1
Removing focus nodes on white space selection.
A quick and easy quality of life you can add to your existing Flutter applications is a common iOS pattern which is not included by default.
A common problem seen in iOS is that of its numeric keyboard. By default it does not include any actions. Which can mean that on the end of forms, your users are left with no way of dismissing a keyboard from the view.
Since the early days of iOS, ways around this have been to wrap your UIView in viewDidLoad
and remove the keyboard manually.
We may as well have this in Flutter as well! And for as simple as one line of code why wouldn’t you?
First we’re going to start by building a common wrapper we will use in all of our pages. In this case we will call if BaseScaffold
however it does not need to provide a scaffold.
Next we will expand our build function to wrap our child and provide an on tap handler. The result should be something like this:
class BaseScaffold extends StatelessWidget {
const BaseScaffold({
required this.child,
this.enableAutoDismissKeyboard = true,
Key? key,
}) : super(key: key);
final bool enableAutoDismissKeyboard;
final Widget child;
@override
Widget build(BuildContext context) {
//! Important - GestureDetector must be above the scaffold
return GestureDetector(
//* Will dismiss the keyboard if white space is tapped on the screen.
onTap: () => onWhiteSpaceTapped(context),
child: Scaffold(
body: child,
),
);
}
void onWhiteSpaceTapped(BuildContext context) {
final FocusScopeNode scope = FocusScope.of(context);
if (scope.hasFocus && enableAutoDismissKeyboard) {
scope.unfocus();
}
}
}
And that’s it!
Now when your users tap anything which doesn’t provide its own focus node (e.g a button or text field), any existing ones will be unfocused. Meaning your users get the same experience they’re used to in iOS and some Android applications.
class HomeView extends StatelessWidget {
const HomeView({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BaseScaffold(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const TextField(
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
hintText: 'No way to dismiss',
),
),
const SizedBox(height: 20.0),
MaterialButton(
onPressed: () {},
child: const Text('Will not dismiss'),
),
],
),
),
);
}
}
As always, code can be found here.
I will aim to do these one a week. So any ideas or common problems you have, get in touch and hopefully we can get something nice and simple in to improve on it.
Ryan