简体   繁体   中英

TextFormField value not updating as intended in flutter

I have a strange problem in my application I have a signup page with several textformfields inside a ListView and the ListView is a child to the Form.

when i reach the last formfield inside the ListView i need to scroll up the screen to actually see what i am typing inside the field. When i do scroll up the textformfields which go out of focus are losing the entered text and are initialised as null. I am not sure what i am missing or do i have to use some other way to make sure i retain the TextFormField values. I have tried to use the controller in every TextFormField then it is retaining the value even if I scroll up. But, the properties of the object eg, hostelData.hostelName are only updated first time and the changes are not reflected in the object property from the second time. I am not so sure what i am missing? Please can someone help me in solving this. Please excuse my mistakes in posting as i am new to programming and any help would be greatly appreciated.

I have posted the code below so that you can reproduce the same problem.

 import 'dart:async';

 import 'package:firebase_auth/firebase_auth.dart';
 import 'package:firebase_database/firebase_database.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';     
 import 'package:myhostel/theme.dart' as Theme;
 import 'package:myhostel/globals.dart' as gl;

 class SignUp extends StatefulWidget {
 const SignUp({ Key key }) : super(key: key);
 @override
  _SignUpState createState() => new _SignUpState();
  }

class HostelData{
 String hostelName = '';
 String ownersName = '';
 String mobileNumber = '';
 String emailId = '';
 String password = '';
 String city = '';
 String hostelType= 'mens';
 String confirmPassword ='';
 }
class _SignUpState extends State<SignUp> {
 HostelData hostelData = new HostelData();

void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
    content: new Text(value),
  duration: const Duration(milliseconds: 3000),

  ));
}

final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
final GlobalKey<FormFieldState<String>> _passwordFieldKey = new 
GlobalKey<FormFieldState<String>>();
bool _autovalidate = false;
bool _formWasEdited = false;

 void _handleSubmitted() {
  final FormState form = _formKey.currentState;
 if (!form.validate()) {
   _autovalidate = true;  // Start validating on every change.
   showInSnackBar('Please fix the errors in red before submitting.');
   } else {
     form.save();
      showInSnackBar('${hostelData.ownersName}\'s hostel name is 
             ${hostelData.hostelName}');
            _createuserwithemailandpassword();
     }
   }
   String _validateName(String value) {
    _formWasEdited = true;
     if (value.isEmpty)
     return 'Name is required.';
     final RegExp nameExp = new RegExp(r'^[A-Za-z ]+$');
     if (!nameExp.hasMatch(value))
     return 'Please enter only alphabetical characters and spaces.';
     return null;
    }
    String _validatePassword(String value) {
      _formWasEdited = true;
       final FormFieldState<String> passwordField = 
       _passwordFieldKey.currentState;
     if (passwordField.value == null || passwordField.value.isEmpty)
     return 'Please choose a password.';
    if (passwordField.value != value)
     return 'Passwords don\'t match';
     return null;
      }
     @override
     Widget build(BuildContext context){

   return new MaterialApp(
   theme: Theme.MyHostelThemeData,
   home: new Scaffold(
    key: _scaffoldKey,

    body: new Container(
      child: new Container(
      decoration: new BoxDecoration(
          image: new DecorationImage(
              image: new AssetImage('assets/bg.png'),
            fit: BoxFit.fill,
          ),
      ),
      child: new Form(

        key: _formKey,
        autovalidate: _autovalidate,


       child: new ListView(
         children: <Widget>[
          new Container(
            margin: const EdgeInsets.only(top:32.0),
            child: new Center(
              child: new Text('SIGN UP',
              style: new TextStyle(
                  color: const Color(0xFFF5FEFD),fontSize:24.0,fontWeight: 
             FontWeight.bold),
            ),
          ),
          ),
      new Row(
            children:[


      new Expanded(
      child: new Container(
        margin: const EdgeInsets.only(left: 24.0,right: 12.0,),

        child:new TextFormField(decoration: new InputDecoration(
            /*hintStyle: new TextStyle(
              fontSize: 20.0,color: const Color(0xFFF5FEFD),),*/
            labelText: 'Hostel Name',
          ),
          /*style: new TextStyle(
            fontSize: 20.0,
            color:  Colors.white,
          ),*/

          onSaved:(String value){ hostelData.hostelName = value; },
          validator: _validateName,
         ),
       ),
      ),
     ],
     ),
     new Row(
            children:[
              /*new Container(
                margin: const EdgeInsets.all(8.0),
                width: 24.0,
                child: new Image.asset(
                  'assets/person_avatar.png',
                  fit: BoxFit.contain,
                  //alignment: FractionalOffset.center,
                ),
              ),*/

              new Expanded(
                child: new Container(
                  margin: const EdgeInsets.only(left: 24.0,right: 12.0,),

                  child:new TextFormField(
                    //controller: _ownersNameController,

                    decoration: new InputDecoration(//hintText: 'Mobile 
             Number',
                     /* hintStyle: new TextStyle(fontSize: 20.0,color: const 
          Color(0xFFF5FEFD),),*/
                      labelText: 'Owners Name',
                    ),

                    /*style: new TextStyle(
                      fontSize: 20.0,
                      color:  Colors.white,
                    ),*/
                 onSaved: (String value) { hostelData.ownersName = value; 
                                                                        },
                    validator: _validateName,
                  ),
                ),
              ),
            ],
          ), 
       new Row(
            children:[



              new Expanded(
                child: new Container(
                  margin: const EdgeInsets.only(left: 24.0,right: 12.0,),

                  child:new TextFormField(
                    //controller: _mobileNumberController,
                    keyboardType: TextInputType.phone,

                    decoration: new InputDecoration(//hintText: 'Mobile 
                     Number',
                      /* hintStyle: new TextStyle(fontSize: 20.0,color: 
                        const Color(0xFFF5FEFD),),*/
                      labelText: 'Mobile Number',
                      //prefixText: '+91',
                    ),

                    /*style: new TextStyle(
                      fontSize: 20.0,
                      color:  Colors.white,
                    ),*/
               onSaved: (String value) { hostelData.mobileNumber = value; },
                    //validator: _validatePhoneNumber,
                  ),
                ),
              ),
            ],
          ),
      //implements EmailID Row
          new Row(
            children:[


              new Expanded(
                child: new Container(
                  margin: const EdgeInsets.only(left: 24.0,right: 12.0,),

                  child:new TextFormField(
                    //controller: _emailIdController,

                    decoration: new InputDecoration(
                      //hintText: 'Mobile Number',
                      /*hintStyle: new TextStyle(fontSize: 20.0,color: const 
                            Color(0xFFF5FEFD),),*/
                      labelText: 'EMail Id',
                      helperText: 'Required',
                    ),
                    /*style: new TextStyle(
                      fontSize: 20.0,
                      color:  Colors.white,
                    ),*/
                    onSaved: (String value){hostelData.emailId = value;},
                  ),
                ),
              ),
            ],
          ),
      //implements the password row

          new Container(
            padding: const EdgeInsets.only(left: 8.0,),
            child: new Row(
              children: <Widget>[
                new Container(
                  margin: const EdgeInsets.only(top: 16.0),
                  //padding: const EdgeInsets.all(8.0),
                  child: new Icon(Icons.lock_outline,
                      color: const Color(0xFFF5FEFD)
                  ),
                ),
                new Expanded(
                  child: new Container(
                    margin: const EdgeInsets.only(
                      left: 28.0, right: 12.0,),
                    child: new TextFormField(
                      key: _passwordFieldKey,
                      //controller: _passwordController,
                      decoration: const InputDecoration(
                        hintText: 'min 8 characters',
                        labelText: 'Password',
                          helperText: 'Required',

                      ),
                      autocorrect: false,
                      //obscureText: true,
                      //validator: 'Required',
                      /*style: DefaultTextStyle.of(context).style.merge(new 
                                       TextStyle(
                              fontSize: 16.0,
                              color: CustomColors.fontColor,
                            ),
                            ),*/
                      onSaved: (String value){hostelData.password = value;},

                    ),
                  ),
                ),
              ],
            ),
          ),
           new Container(
            padding: const EdgeInsets.only(left: 8.0,),
            child: new Row(
              children: <Widget>[
                new Container(
                  margin: const EdgeInsets.only(top: 16.0),
                  //padding: const EdgeInsets.all(8.0),
                  child: new Icon(Icons.lock_outline,
                      color: const Color(0xFFF5FEFD)
                  ),
                ),
                new Expanded(
                  child: new Container(
                    margin: const EdgeInsets.only(
                      left: 28.0, right: 12.0,),
                    child: new TextFormField(
                      //controller: _confirmpasswordcontroller,
                      decoration: const InputDecoration(
                        labelText: 'Confirm Password',
                       helperText: 'Required'


                      ),
                      autocorrect: false,
                     // obscureText: true,
                      //validator: 'Required',
                      /*style: DefaultTextStyle.of(context).style.merge(new 
                    TextStyle(
                              fontSize: 16.0,
                              color: CustomColors.fontColor,
                            ),
                            ),*/
                      //onSaved: (String value){hostelData.confirmPassword = 
                                                value;},

                      validator: _validatePassword,
                    ),
                  ),
                ),
              ],
            ),
          ),
          new Row(
            children:[

              new Expanded(
                child: new Container(
                  margin: const EdgeInsets.only(left: 24.0,right: 12.0,),

                  child:new TextFormField(
                    controller: _cityController,

                    decoration: new InputDecoration(labelText: 'City*'),

                    onSaved: (String value){hostelData.city = value;},
                    validator: _validateName,
                  ),
                ),
              ),
            ],
          ),
         new Container(
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.only(left:24.0,right: 24.0),
            decoration: new BoxDecoration(
              border: new Border.all(
                color: Colors.white,
                width: 2.0,
              ),
              borderRadius: new BorderRadius.all(const 
                    Radius.circular(32.0),)
            ),
        child: new FlatButton(
          onPressed: ((){
            print('SignUp Button Clicked');
             _handleSubmitted();
          }),
          child: new Text (
            'SIGN UP',
            style: new TextStyle(fontSize: 24.0,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
          ),
        ),
       ),
          new Row(
            children:[


                new Container(
                  margin: const EdgeInsets.only(left: 24.0,bottom: 12.0),

                  child:new Text(
                    'Already have an account?',
                       style: new TextStyle(
                      fontSize: 20.0,
                      color:  Colors.white,
                    ),
                  ),
                ),

              new Container(
                padding: const EdgeInsets.only(right: 8.0,top: 
                    4.0,bottom:16.0),
                margin: const EdgeInsets.only(right: 12.0,left: 4.0),
                child:
              new MaterialButton(
                onPressed: ((){
                //Sign In Button pressed declaration here
                print('sign in button clicked');

              }),
                  child: new Text('SignIn',
                  style: new TextStyle(
                    fontSize: 16.0,
                    color: Colors.teal[200],
                    ),
                     ),
                minWidth: 16.0,
              ),
              ),

            ],
          ),
          new Container(
            padding: const EdgeInsets.only(left: 16.0),
            child: new Text('* indicates required field',
                style: new TextStyle(
                  fontSize: 14.0,
                  color: Colors.white,
                ),),
          ),
       ]
      ),
       ),
      ),

     ),

    ),

    );

  } // widget ends here

globals.dart

library my_hostel.globals;

 import 'package:firebase_auth/firebase_auth.dart';
 import 'package:firebase_database/firebase_database.dart';



   final FirebaseAuth auth = FirebaseAuth.instance;

 final DatabaseReference messagesRef =FirebaseDatabase.instance.reference();

Here is an example of working code:

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  String s1 = "";
  String s2 = "";
  String s3 = "";
  String s4 = "";
  String s5 = "";

  final TextEditingController c1 = new TextEditingController();
  final TextEditingController c2 = new TextEditingController();
  final TextEditingController c3 = new TextEditingController();
  final TextEditingController c4 = new TextEditingController();
  final TextEditingController c5 = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("Example"),),
      body: new ListView(
        children: <Widget>[
          new Padding(padding: new EdgeInsets.all(70.0),),
          new TextField(
            controller: c1,
            onChanged: (String text) {
              s1 = text;
            },
          ),
          new Padding(padding: new EdgeInsets.all(70.0),),
          new TextField(
            controller: c2,
            onChanged: (String text) {
              s2 = text;
            },
          ),
          new Padding(padding: new EdgeInsets.all(70.0),),
          new TextField(
            controller: c3,
            onChanged: (String text) {
              s3 = text;
            },
          ),
          new Padding(padding: new EdgeInsets.all(70.0),),
          new TextField(
            controller: c4,
            onChanged: (String text) {
              s4 = text;
            },
          ),
          new Padding(padding: new EdgeInsets.all(70.0),),
          new TextField(
            controller: c5,
            onChanged: (String text) {
              s5 = text;
            },
          ),
        ],
      )
    );
  }
}

You need to add a TextEditingController with your TextField . Listview removes invisible widgets because rendering a ton of widgets that are not being displayed would make it perform worse!

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