1
votes

I have a Form with quite a few TextFormFields inside it and (for now) a single DropDownButton.

When I tap into one of the TextFormFields, the keyboard flashes but will not stay up. The only workaround I have found is to start typing on my computer's keyboard to get the phone keyboard to pop up on its own - obviously not typing into anywhere - and then, while the keyboard is already up, tap into the TextFormField and then I am able to enter in text, but as soon as I tap out out of that field, the entered text disappears. This bandaid is ineffective on all fields other than Name, because their keyboardTypes are number pads. So, since typing neither letters or numbers summons this keyboard on the phone, it is impossible to get the keyboard for these fields to materialize.

I'm sure that the Form is the issue because with the same layering, if I change the Padding's child to go directly to the same ListView, all of the TextFormField issues go away.

I chose not to include the relevant code for my DropDownButton issue, because it is likely unrelated, since it is the only problem that does not resolve when I temporarily remove the Form widget.

Keyboard will not pop

With temporary workaround, entered text still will not remain after exiting field

DropDownButton wont display selected value

class NewPage extends MaterialPageRoute<Null>{
 final formKey = GlobalKey<FormState>();
 String _name;

 void _submit(){
  final form = formKey.currentState;
  if(form.validate()){
   form.save();
   print("$_name");
  }
 }
 final name = TextFormField(
  //all other TextFormFields are declared as name is
  validator: (val) =>
   val.isEmpty? "Name can't be empty.': null,
  onSaved: (val) => _name = val,
  decoration: InputDecoration(
   labelText: "Name",
   labelStyle: TextStyle(
    fontSize: 20.0,
   ),
   contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 12.0),
   border: OutlineInputBorder(
    borderRadius: BorderRadius.circular(20.0),
   )
  )
 );
 final age = TextFormField(
  keyboardType: TextInputType.number,
  validator: null,
  decoration: InputDecoration(
   labelText: "Age",
   labelStyle: TextStyle(
    fontSize: 20.0,
   ),
   contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 12.0),
   border: OutlineInputBorder(
    borderRadius: BorderRadius.circular(20.0),
   )
  ),
 );
 return Scaffold(
  body: Padding(
   padding: EdgeInsets.symmetric(horizontal: 20.0),
   child: new Form(
    key: formKey,
     child: new ListView(
      children: <Widget> [
       SizedBox(height: 100.0),
       name,
       SizedBox(height: 20.0),
       new Text("Sex:"),
       sex,
       SizedBox(height: 20.0),
       age,
       //and so on
       new RaisedButton(
        onPressed: _submit,
        child: new Text("Go"),
       ),
      ],
     ),
   ),
  ),
 );
}
2

2 Answers

1
votes

I believe the issue may stem from class NewPage extends MaterialPageRoute<Null>. Unless you're making a new subclass of route to change the route's behaviour significantly, you shouldn't be extending from it - if you're extending it, it will be after you have a deep understanding of how flutter works.

I believe what you're looking to do is instead extend StatefulWidget and make a corresponding State<>. If you need to make a Route for some reason, you can still pass in a builder that does what you need i.e. new MaterialPageRoute(builder: (context) => new NewPage()).

This works for me when I run it in the simulator. I added in the dropdown too just for fun =D.

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

void main() => runApp(new MaterialApp(home: new NewPage()));

class NewPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new NewPageState();
}

class NewPageState extends State<NewPage> {
  final formKey = GlobalKey<FormState>();
  String _name;

  String _sex;

  void _submit() {
    final form = formKey.currentState;
    if (form.validate()) {
      form.save();
      print("$_name");
    }
  }

  @override
  Widget build(BuildContext context) {
    final name = TextFormField(
      //all other TextFormFields are declared as name is
      validator: (val) => val.isEmpty ? "Name can't be empty." : null,
      onSaved: (val) => _name = val,
      decoration: InputDecoration(
        labelText: "Name",
        labelStyle: TextStyle(
          fontSize: 20.0,
        ),
        contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 12.0),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(20.0),
        ),
      ),
    );
    final age = TextFormField(
      keyboardType: TextInputType.number,
      validator: null,
      decoration: InputDecoration(
        labelText: "Age",
        labelStyle: TextStyle(
          fontSize: 20.0,
        ),
        contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 12.0),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(20.0),
        ),
      ),
    );
    final sex = DropdownButton(
      items: [
        new DropdownMenuItem(child: new Text("Male"), value: "male"),
        new DropdownMenuItem(child: new Text("Female"), value: "female"),
        new DropdownMenuItem(child: new Text("Other"), value: "other"),
      ],
      onChanged: (val) => setState(() => _sex = val),
      value: _sex,
    );
    return new Scaffold(
      body: Padding(
        padding: EdgeInsets.symmetric(horizontal: 20.0),
        child: new Form(
          key: formKey,
          child: new ListView(
            children: <Widget>[
              SizedBox(height: 100.0),
              name,
              SizedBox(height: 20.0),
              new Text("Sex:"),
              sex,
              SizedBox(height: 20.0),
              age,
              //and so on
              new RaisedButton(
                onPressed: _submit,
                child: new Text("Go"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

If this doesn't solve the issue, some extra information such as the device you're using would be helpful. Also, posting a code example that actually compiles would help us help you - I'd advise checking that before posting the question next time.

0
votes

don't wrap all the TextFormFields in the same Form. It's not a good practice and causes a lot of problems.

Wrap each field individually and make sure to use different keys. Validate them separately. And try using the onChanged method or the onEditingComplete method to save the string immediately, instead of onSaved method.

Also, you're saving the value only if it is valid. Don't do that, it might be the problem.