Q:

How Validate TextFormField in ExpansionTile in Flutter?

I’m new to Flutter. I have multiple ExpansionTiles. I want to validate the TextFormFields inside the ExpansionTile. When user direct click submit button it’s not validating the TextFormFields and submitting.
Here is my code
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final GlobalKey<FormState> _formkey = GlobalKey();
  TextEditingController _email=TextEditingController();
  TextEditingController _address=TextEditingController();
  TextEditingController _userName=TextEditingController();
  TextEditingController _mobile=TextEditingController();
  bool _userNameAutoValidate = false;
  bool _emailAutoValidate = false;
  bool _addressAutoValidate = false;
  bool _mobileAutoValidate = false;
  void _submit(){
     if (!_formkey.currentState.validate()) {
        return;
      }
    _formkey.currentState.save();
    print("_userName = ${_userName.text}");
    print("_email = ${_email.text}");
    print("_address = ${_address.text}");
    print("_mobile = ${_mobile.text}");
  }
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Expansion Form Example",
      home: Scaffold(
        appBar: AppBar(
          title: Text('Expansion Form Example'),
        ),floatingActionButton: FloatingActionButton(
        child: Text("Submit"),
        onPressed: () {
          _submit();
        },
      ),
        body: Center(
          child: Form(
            key: _formkey,
            child: ListView(
              children: <Widget>[
                ExpansionTile(
                  title: Text("User Info"),
                  children: <Widget>[
                    Focus(
                      onFocusChange: (value) {
                        if (!value) {
                          setState(() {
                            _userNameAutoValidate = true;
                          });
                        }
                      },
                      child: TextFormField(
                        autovalidate: _userNameAutoValidate,
                        controller: _userName,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                            hintText: "enter user name",
                            labelText: "User Name",
                            border: OutlineInputBorder()),
                        validator: (value) {
                          if (value.isEmpty) {
                            return "User Name field cannot be empty.";
                          }
                          return null;
                        },
                      ),
                    ),
                    Focus(
                      onFocusChange: (value) {
                        if (!value) {
                          setState(() {
                            _emailAutoValidate = true;
                          });
                        }
                      },
                      child: TextFormField(
                        autovalidate: _emailAutoValidate,
                        controller: _email,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                            hintText: "enter email",
                            labelText: "Email",
                            border: OutlineInputBorder()),
                        validator: (value) {
                          if (value.isEmpty) {
                            return "Email field cannot be empty.";
                          }
                          return null;
                        },
                      ),
                    ),
                  ],
                ),
                ExpansionTile(
                  title: Text("Address Info"),
                  children: <Widget>[
                    Focus(
                      onFocusChange: (value) {
                        if (!value) {
                          setState(() {
                            _addressAutoValidate = true;
                          });
                        }
                      },
                      child: TextFormField(
                        autovalidate: _addressAutoValidate,
                        controller: _address,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                            hintText: "enter address",
                            labelText: "Address",
                            border: OutlineInputBorder()),
                        validator: (value) {
                          if (value.isEmpty) {
                            return "Address field cannot be empty.";
                          }
                          return null;
                        },
                      ),
                    ),
                  ],
                ),
                ExpansionTile(
                  title: Text("Other Info"),
                  children: <Widget>[
                    Focus(
                      onFocusChange: (value) {
                        if (!value) {
                          setState(() {
                            _mobileAutoValidate = true;
                          });
                        }
                      },
                      child: TextFormField(
                        autovalidate: _mobileAutoValidate,
                        controller: _mobile,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                            hintText: "enter mobile number",
                            labelText: "Mobile Number",
                            border: OutlineInputBorder()),
                        validator: (value) {
                          if (value.isEmpty) {
                            return "Mobile Number cannot be empty.";
                          }
                          return null;
                        },
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

How to validate the TextFormFields when ExpansionTile is close.
How to do it in manually?
please help me.
Thankyou

A:

Previously, Expansion Tile did not maintain state by default. Here is the PR which resolved this issue https://github.com/flutter/flutter/pull/57172/files.
So you need to pass maintainState: true to maintain the state under Expansion Tile. And it will validate the form even if tile is collapsed.

