flutterandroid-softkeyboardform-fields

Flutter TextFormFields clear when dismissing keyboard


Pretty much what I describe in the title. I have a pile of TextFormFields populated from Firebase when the app launches.

The user should be able to update these, and when they are done, click a submit button to update the database. The database code all works, however there is some bug which works as follows:

TextFormField1:   "New Text Entered"
TextFormField2:   "Some more text"
TextFormField3:   "Another update here"

Now we get to a point where we need to dismiss the keyboard, so that we can see the submit button underneath. As soon as you click the little down arrow to dismiss the keyboard, all the changes above revert back to their original state.

Anyone seen this?

I am prepopulating the data in these fields at runtime, and you can edit and update the text, and it all works fine... except if you minimise the keyboard.

Please tell me that Flutter isn't doing something fundamentally stupid like reloading the widget underneath from scratch every time you ask the keyboard to go away...... It sort of feels like it is.


Solution

  • Yes. It happens to me all the time. It is because the screen rebuilds when the bottom insets (due to keyboard) changes.

    1. Enclose the TextFormField(s) inside a Form and give it a global key.
    2. Use a local variable to store the value of the TextFormField. Update it in onChanged method. All done!

    I shall attach a code for easiness.

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: LoginScreen(),
        );
      }
    }
    
    // Login Screen
    class LoginScreen extends StatefulWidget {
      @override
      _LoginScreenState createState() => _LoginScreenState();
      static GlobalKey<FormState> _loginScreenFormKey = GlobalKey<FormState>();
    }
    
    class _LoginScreenState extends State<LoginScreen> {
      String username;
      String password;
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
            body: Form(
              key: LoginScreen._loginScreenFormKey,
              child: Column(
                children: [
                  TextFormField(
                    decoration: InputDecoration(
                      hintText: 'Enter username',
                    ),
                    onChanged: (value) {
                      setState(() {
                        username = value;
                      });
                    },
                  ),
                  TextFormField(
                    decoration: InputDecoration(
                      hintText: 'Enter username',
                    ),
                    onChanged: (value) {
                      setState(() {
                        password = value;
                      });
                    },
                    obscureText: true,
                  ),
                  RaisedButton(
                    onPressed: () {
                      LoginScreen._loginScreenFormKey.currentState.save();
                    },
                    child: Text('submit'),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }