Flutter: Moving TextFormField focus with soft keyboard

Last updated on November 2, 2020 The Frog Loading... Post a comment

In Flutter, the user can shift the focus between multiple TextFormFields inside a Form by using the soft keyboard (not by tapping the TextFormFields). This article shows you 2 ways to do so.

1. FocusScope.of(context).nextFocus()

This method is simple to implement.

Sample code:

SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(25),
            child: Form(
              child: Column(children: [
                TextFormField(
                  textInputAction: TextInputAction.next,
                  decoration: InputDecoration(labelText: 'Email'),
                  onEditingComplete: () => FocusScope.of(context).nextFocus(),
                ),
                SizedBox(height: 25),
                TextFormField(
                    textInputAction: TextInputAction.next,
                    decoration: InputDecoration(labelText: 'Name'),
                    onEditingComplete: () =>
                        FocusScope.of(context).nextFocus()),
                SizedBox(height: 25),
                TextFormField(
                    textInputAction: TextInputAction.next,
                    decoration: InputDecoration(labelText: 'Address'),
                    onEditingComplete: () =>
                        FocusScope.of(context).nextFocus()),
                SizedBox(height: 25),
                TextFormField(
                    textInputAction: TextInputAction.done,
                    decoration: InputDecoration(labelText: 'Job'),
                    // This is the last text field so there is no need to move the focus 
                    onEditingComplete: () =>
                        FocusScope.of(context).unfocus()
                  )
              ]),
            ),
          ),
        )

Output:

2. FocusScope.of(context).requestFocus()

This method is more complicated than the first one but it’s more customizable. You can drive the focus to any TextFormField you want to, not just the next one.

Example:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Hide the debug banner
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _formKey = GlobalKey<FormState>();
  FocusNode _nameFocusNode;
  FocusNode _addressFocusNode;
  FocusNode _jobFocusNode;

  // Create the focus nodes
  @override
  void initState() {
    _nameFocusNode = FocusNode();
    _addressFocusNode = FocusNode();
    _jobFocusNode = FocusNode();
    super.initState();
  }

  // Clean the focus nodes
  @override
  void dispose() {
    _nameFocusNode.dispose();
    _addressFocusNode.dispose();
    _jobFocusNode.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text(
            'Kindacode.com',
          ),
        ),
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(25),
            child: Form(
              key: _formKey,
              child: Column(children: [
                TextFormField(
                  textInputAction: TextInputAction.next,
                  decoration: InputDecoration(labelText: 'Email'),
                  onFieldSubmitted: (_) =>
                      FocusScope.of(context).requestFocus(_nameFocusNode),
                ),
                SizedBox(height: 25),
                TextFormField(
                    textInputAction: TextInputAction.next,
                    decoration: InputDecoration(labelText: 'Name'),
                    focusNode: _nameFocusNode,
                    onFieldSubmitted: (_) =>
                        FocusScope.of(context).requestFocus(_addressFocusNode)),
                SizedBox(height: 25),
                TextFormField(
                    textInputAction: TextInputAction.next,
                    decoration: InputDecoration(labelText: 'Address'),
                    focusNode: _addressFocusNode,
                    onFieldSubmitted: (_) =>
                        FocusScope.of(context).requestFocus(_jobFocusNode)),
                SizedBox(height: 25),
                TextFormField(
                  textInputAction: TextInputAction.done,
                  focusNode: _jobFocusNode,
                  decoration: InputDecoration(labelText: 'Job'),
                  // This is the last text field so there is no need to move the focus
                )
              ]),
            ),
          ),
        ));
  }
}

Output:

That’s all. Happy coding 🙂

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles