53

Sign up form with flutter

I'm trying to build an app front end with flutter and it's my first time so I faced some bugs like this one: there is no way to edit my textformfield because I putted my form elements in a listview ! when keyboard appears to enter some text to the field it disappears in a second ! I need an immediat solution please :(

import 'package:flutter/material.dart';
import'package:dubai274_app/mobile_verif.dart';
import 'EnsureVisible.dart';
class SignUp extends StatefulWidget{
  static String tag = 'Sign_up-page';
  SignUp_Page createState() => SignUp_Page();

}
class SignUp_Page extends State<SignUp>{
  


  List<DropdownMenuItem<String>> _Dropdownmenuitems;
  String _statusSel;
  List<DropdownMenuItem<String>> _getDropdownmenuitem(){

    List<DropdownMenuItem<String>> items=new List();
    items.add(new DropdownMenuItem(value:'Emirates',child: new Text('United Arab Emirates')));
    items.add(new DropdownMenuItem(value:'Tun',child: new Text('Tunisia')));
    return items;
  }
  void changeddropdowselecteditem(String selecteditem){
    setState(() {
_statusSel=selecteditem;
    });
  }
   @override
  void initState() {
    // TODO: implement initState
    //listViewController=new ScrollController().addListener(_scrollListener);
    _Dropdownmenuitems=_getDropdownmenuitem();
    _statusSel=_Dropdownmenuitems[0].value;
  }
@override
  Widget build(BuildContext context) {
  final scaffoldKey = GlobalKey<ScaffoldState>();
  final formKey = GlobalKey<FormState>();
  final TextEditingController _controller = new TextEditingController();
  
final first_value=TextFormField(autofocus: false,
  validator: (val) =>
  val.length < 6 ? 'First name required' : null,
  decoration: InputDecoration(
    labelText: 'First Name',
    hintText: 'First Name',
    contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),


  ),);

final family_value=TextFormField(autofocus: false,
  decoration: InputDecoration(
    labelText: 'Last Name',
    hintText: 'Last Name',
    contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),


  ),);

final Nationality=new DropdownButton(items: _Dropdownmenuitems, value:_statusSel,onChanged: changeddropdowselecteditem);

final email_value=TextFormField(keyboardType: TextInputType.emailAddress,
  autofocus: false,
  decoration: InputDecoration(
    labelText: 'Email',
    hintText: 'Email',
    contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),

  ),);

final password=Column(children: <Widget>[ TextFormField(autofocus: false,

  obscureText: true,
  decoration: InputDecoration(
    labelText: 'Password',
    hintText: 'Password',
    contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),)), Text('Min 8 characters with at least one special character')]);
  void _performsignup() {

    final snackbar = SnackBar(
      content: Text('Email: $email, password: $password'),
    );

    scaffoldKey.currentState.showSnackBar(snackbar);
  }
  void _submit() {
    final form = formKey.currentState;

    if (form.validate()) {
      form.save();
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => MobileVerif()),
      );

      _performsignup();
    }
  }
final forward_signedin=FloatingActionButton(tooltip: 'Go forward',
  child: Icon(Icons.arrow_forward,color: Colors.white,size: 38.4,),


  onPressed: (){_submit();},);

return MaterialApp(
      title: 'Sign_Up_Page',
      home: Scaffold(
        appBar: AppBar(
          elevation: 0.0,
      backgroundColor: Colors.transparent,
      title: const Text('Sign Up',style: TextStyle(color: Colors.blueAccent, fontSize: 25.0,fontWeight: FontWeight.bold),textAlign: TextAlign.center,),
  centerTitle: true,
  leading: IconButton(
  tooltip: 'Previous choice',
  icon: const Icon(Icons.arrow_back_ios),
    onPressed: () { Navigator.pop(context);},
    color: Colors.black,
    iconSize: 20.0,
  ),
  ),
        body: new Container(
          decoration: new BoxDecoration(
          image: new DecorationImage(
            image: new AssetImage("assets/background.png"),
            fit: BoxFit.cover,
          ),
        ),
        child: new Form( key: formKey,
            child: new Padding( padding: new EdgeInsets.all(40.0), child: ListView(
      children: <Widget>[

       first_value,
       family_value,
       Nationality,
       email_value,
       password,
       new ListTile( title:forward_signedin,)],
)) )

        ),


        ),

      );


  }
}
cizario
  • 3,995
  • 3
  • 13
  • 27
Farah Bédoui
  • 863
  • 2
  • 7
  • 8

16 Answers16

89

You have the following code in your build function:

final formKey = GlobalKey<FormState>();

This is the problem. You have to either make it static or move to initState()

taras
  • 6,566
  • 10
  • 39
  • 50
apc
  • 1,152
  • 12
  • 9
  • 3
    I ran into a similar issue. Basically, I have a form that I wanted to reuse so I created a separate widget. Then from wherever I use that widget, I passed down the GlobalKey to the widget. One form would work fine and the other would exhibit the keyboard dismissal behavior. However, the creation of the key was NOT in the build method. Creating the key as static as you suggested seemed to fix it but no clue why... – jdixon04 Nov 04 '19 at 01:23
  • 5
    anyone care to explain why this is happening when not declaring it into static? – Moralde-Sama May 30 '20 at 02:07
  • 1
    This happens when you put GlobalKey in your build function – CodingEra Jul 11 '21 at 17:40
  • 1
    Static makes it have no business to do with the class' activites @Moralde-Sama. can anyone push this explanation further? – emanuel sanga Jan 05 '22 at 16:15
  • Exactly my problem, had the `formKey` in `Widget build(BuildContext context)` insted of my `StatefulWidget`'s `class _MyClassState extends State` – Francois May 09 '23 at 16:46
25

I had the same problem and as @apc said just make the key static or intialize it in iniState()...

if you use stateless widget make it static

static final GlobalKey<FormState> _key = GlobalKey<FormState>();

Jkhaled
  • 435
  • 5
  • 7
13

Having a GlobalKey for the form didn't do it for me. What helped was this github comment. Essentially, having a MediaQuery.of(context) for getting the size of the screen causes rebuilds that make the textfield lose focus. In my case, the MediaQuery accessing widget was very high up the widget tree. I had to look it up and replace it with LayoutBuilder.

class ScreenSizeGetter extends StatelessWidget {
  const ScreenSizeGetter({Key? key, required this.child}) : super(key: key);
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
          double screenWidth = constraints.maxWidth;
          double screenHeight = constraints.maxHeight;
          
          // Can pass these sizes down to the child by Bloc pattern or other ways
          return child;
      },
    );
  }
}
Srikanth
  • 2,014
  • 19
  • 22
  • 1
    This was the issue for me! I replaced my `MediaQuery.of(context).size.width` with a LayoutBuilder and `viewportConstraints.maxWidth` – Emile Haas May 31 '22 at 11:30
11

If you are using StatelessWidget, transform it into StatefulWidget. Make sure the key is state's property, not widget's. This happens because your form key is getting recreated over and over again with each rebuild. To keep the key, it should be a part of state.

Artem Deviatov
  • 970
  • 12
  • 20
7

I'm going to post my answer here, even though it is not exactly the same as problem as the OP.

I searched the internet high and low for this issue of the keyboard appearing and disappearing, and
1. this was the only SO question I found that describes the keyboard appear disappear issue, and
2. the other solutions out there, like @apc's answer and this github answer are all focused on the formKey being static and/or a GlobalKey, and that was definitely not the cause of my problem (having unchanging keys or re-created keys for my form, and/or it's fields, had no effect at all on the issue).

My specific problem involved a class AuthService with ChangeNotifier with a number of Future methods.
After literally days of trying different approaches I found that the only way that I could avoid the keyboard-appearing-and-instantly-disappearing-on-form-field-focus issue was to have the AuthService() be at the top level of my app, in runApp() :

void main() => runApp(
  ChangeNotifierProvider<AuthService>(
    child: TheWidgetThatIsMyAppAndHasAllBusinessLogicInIt(),
    builder: (BuildContext context) {
      return AuthService();
    },
  ),
);

(Having the ChangeNotifierProvider anywhere else in the code has the keyboard disappear issue)

I've then had to get creative about how I structured my logic under this - because I only really care about the AuthService in certain parts of my application, but I'm very new to Flutter and it's all been good learning.

I don't know why this is, and I'd love to learn more, and I know I haven't spelled out my full situation.....
but I've spent literally days solving this, I needed to put my answer here to hopefully help others.

kris
  • 11,868
  • 9
  • 88
  • 110
  • ```builder``` is now depracted. Please use ```create``` instead – Yonko Kilasi Jul 21 '20 at 18:08
  • 1
    The problem can also be caused by calling `setState()` within `TextController.addListener()` or the TextField's `onChanged()` method when the TextField is a descendant of [`VisibilityDetector`](https://pub.dev/packages/visibility_detector). – Stack Underflow Oct 19 '21 at 22:12
  • When I call the notifyListeners() method in the TextField onChanged event, I encounter the problem that the keyboard closes. making formkey static final solves the problem of closing the keyboard. However, when I press the back key and reopen the form, the values in the textField are not cleared, although I reset the values in the provider. I think that the value in the TextEditingController is not cleared. I didn't have such a problem when I defined Formkey in my build method. Why does the problem arise and how can I solve this problem? – Gülsen Keskin Sep 01 '22 at 04:21
4

You should define all of the these:

  final scaffoldKey = GlobalKey<ScaffoldState>();
  final formKey = GlobalKey<FormState>();
  final TextEditingController _controller = new TextEditingController();

as fields of the SignUp_Page not at build function.

Mohamed Reda
  • 1,207
  • 13
  • 21
1

In my own case, I had this key: ValueKey<int>(math.Random().nextInt(5)), as the key for an ancestor widget of the TextFormField. I removed it and the error no longer appeared. So my debug suggestion is to check all widgets, in the widget tree, that has any value passed for its key argument..

Ercross
  • 519
  • 6
  • 17
1

In my case the problem had two parts:

  1. The TextField had a FutureBuilder above it in the StatefulWidget's build tree.
  2. The TextField called setState in its onChanged event handler.

It seems every time setState was called the FutureBuilder rebuilt its tree, causing the TextField to lose focus. I moved the FutureBuilder up the tree so it was outside the StatefulWidget and the problem disappeared.

Isaac Lyman
  • 2,175
  • 1
  • 22
  • 42
0

If your TextField is in a Dismissible() widget then this cause the problem!

GILO
  • 2,444
  • 21
  • 47
0

FWIW my issue was different than the accepted answer. I was refactoring code and accidentally copied a Key value into two places, so I had two text fields w/ the same key. This resulted in the behavior described by OP. By ensuring all of my Widget keys were unique, I was able to resolve this issue.

Jake Boomgaarden
  • 3,394
  • 1
  • 17
  • 31
0

FWIW+1: I was using Router with Beamer and the page on top of the stack was not const. Const'ing the top page resolved it. No other change, just a const keyword in front of the Page on top of the stack...

Gazihan Alankus
  • 11,256
  • 7
  • 46
  • 57
0

After hours of research the solution that worked for me is to put the declaration of my Texteditindcontroller in static final and outside of my build method, i.e. just after the declaration of my class which extends to stateless widget

0

For anyone using multiple dynamically produced TextField:

I still faced errors even if I use a UniqueKey on Dismissible.

I then used Key(MyObject[index].id) with an ID using UUID to have unique keys that can be assigned to Dismissible, which led to the TextField closing upon taking in a single value (keyboard may be closing automatically due to touch events).

Finally, I switched to the Flutter_Swipable package, and that resolved my issue!

user16217248
  • 3,119
  • 19
  • 19
  • 37
0

This may be caused of the screen to be redrawn when the widget height is changed when the keyboard appears.

Look here for a solution suggestion to prevent the keyboard to alter (underneath) view size.

When the keyboard appears, the Flutter widgets resize. How to prevent this?

Roar Grønmo
  • 2,926
  • 2
  • 24
  • 37
0

In my case the error was call to...

FocusScope.of(context).unfocus();

... when validate form without checking if the keyboard was or not visible. By comment that instruction the error disappears.

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 02 '23 at 13:32
0

simple if you are using a Stateless widget then just use static like this:

from

final GlobalKey _formKey = GlobalKey();

to

static final GlobalKey _formKey = GlobalKey();

and from

final TextEditingController _usernameController = TextEditingController();

to 

static final TextEditingController _usernameController = TextEditingController();

Syed Rehan
  • 651
  • 1
  • 3
  • 11