FocusScope.nextFocus() unexpectedly skips one or more TextFormFields

1,267

Solution 1

Flutter 1.22 includes a change to automatically advance the focus when you use textInputAction: TextInputAction.next. However, they didn't update the documentation.

If you specify both onFieldSubmitted and textInputAction, it does not work because it has the effect of calling nextFocus twice. So, the Flutter change was a breaking change.

You don't need to specify the onEditingComplete callback and handle it manually. Just TextInputAction.next is enough by itself.

The relevant Flutter change is here. Also, some discussion here.

Note in the description of the Flutter change it says, "Focus will be moved automatically if onEditingComplete is not specified, but must by moved manually if onEditingComplete is specified."

Solution 2

onEditingComplete() should work in your case, not sure why onSubmitted() not working it should be working, might be a defect on latest version

Column(children: <Widget>[
        TextFormField(
          onEditingComplete: () => FocusScope.of(context).nextFocus(),
          textInputAction: TextInputAction.next,
        ),
        TextFormField(
          onEditingComplete: () => FocusScope.of(context).nextFocus(),
          textInputAction: TextInputAction.next,
        ),
        TextFormField(
          onEditingComplete: () => FocusScope.of(context).nextFocus(),
          textInputAction: TextInputAction.next,
        ),
        TextFormField(
          onEditingComplete: () => FocusScope.of(context).nextFocus(),
          textInputAction: TextInputAction.next,
        ),
        TextFormField(
          textInputAction: TextInputAction.done,
        ),
      ]),
Share:
1,267
Giorgio
Author by

Giorgio

Computer scientist

Updated on December 24, 2022

Comments

  • Giorgio
    Giorgio over 1 year

    I would like to have a series of TextFormFields that the user can navigate by pressing "next" on the soft keyboard (or by pressing tab on the hard keyboard, when testing on an emulator). I was expecting the following Flutter app to work:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'TextFormField Problem Demo',
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Test Homepage'),
          ),
          body: Column(children: <Widget>[
            TextFormField(
              onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
              textInputAction: TextInputAction.next,
            ),
            TextFormField(
              onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
              textInputAction: TextInputAction.next,
            ),
            TextFormField(
              onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
              textInputAction: TextInputAction.next,
            ),
            TextFormField(
              onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
              textInputAction: TextInputAction.next,
            ),
            TextFormField(
              textInputAction: TextInputAction.done,
            ),
          ]),
        );
      }
    }
    

    ... But pressing tab (on DartPad) or pressing "next" (on the soft keyboard of an emulator) jumps to a seemingly random field, instead of jumping to the next one. More specifically, it looks like FocusScope.of(context).nextFocus() "skips" one field (or more fields, sometimes, depending on the run) instead of just going to the next field.

    I was assuming that nextFocus() can automatically figure out what is the next focusable widget among the children of my Column, even without explicitly having to specify the focusNode property of my TextFormFields (as seen in another post on StackOverflow). Why is this not the case? Thank you for any input.

    I am using Flutter 1.22 on an Android emulator (and on Dartpad).

  • Giorgio
    Giorgio over 3 years
    Thank you for your answer. For some strange reason, onEditingComplete solves my problem on the Android emulator but not on DartPad. I'm currently double-checking if there might be some other mistake I have made..
  • Jitesh Mohite
    Jitesh Mohite over 3 years
    I don't think it will work on the dart pad, there is an issue with the keyboard there, just run on a real device if works. The problem will be solved. if works, accept the answer so that others can find it useful.
  • Giorgio
    Giorgio over 3 years
    Thank you. Are you sure there is an issue with DartPad's keyboard? Would you mind adding a link to where you found this problem (or to explain the problem)? If there's an issue with DartPad then I can very gladly mark your answer as accepted, but I should first make sure that there is such an issue, if you don't mind.
  • Jitesh Mohite
    Jitesh Mohite over 3 years
    On DartPad when I click it even not open the keyboard sometimes, I cannot provide you official docs for it. But I think if it's working on all real devices then there is no issue. It's an online emulator kind of web portal, so don't just depend on it.
  • Giorgio
    Giorgio over 3 years
    Thank you for the detailed answer and for the links. Trying to only set textInputAction on DartPad (currently running Flutter 1.23) unfortunately still shows the same problem. I will try the same on an Android emulator as soon as I can. Moreover, as stated in the question, the number of fields that are "skipped" is unfortunately not just 1, but a seemingly random number: could it be that there is another, different problem from the one you are mentioning?
  • Ryan Jones
    Ryan Jones over 3 years
    @Giorgio I tested the solution on both Android and iOS emulators, and it works for me. According to the Flutter engineer, it will skip just 1 field when you specify both. For example, see here: github.com/flutter/flutter/issues/68571#issuecomment-7168354‌​54 And here: github.com/flutter/flutter/issues/68571#issuecomment-7168675‌​36
  • Ryan Jones
    Ryan Jones over 3 years
    He did say "roughly equivalent to calling nextFocus() twice", so maybe roughly is a clue that it won't always behave the same way. Just a guess, I haven't checked the Flutter source code.
  • ruclip
    ruclip over 3 years
    Thaaaank you for the hint!