简体   繁体   中英

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.

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'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

This is my solution: move the TextEditingController variable from the inside of the "build" method to the outside of the "build" method. Ref in pic The solution

The class that includes those TextFormFields should extends State of StatefulWidget, the local state will be cleared if the dismiss of keyboard causes those fields re-render, hence you need StatefulWidget to save the local state so that it won't be re-rendered

Convert you StatelessWidget to StatefulWidget.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM