带有嵌套小部件的Flutter表单验证

时间:2020-09-15 14:42:59

标签: flutter

因此对于我的注册屏幕,我必须填写两个TextFormField用户:电子邮件和密码。因为我使用相同的样式,所以我想将TextFormField重构为单独的小部件。在主窗口小部件中,当用户按下“注册”按钮时,我要验证所有三个字段。我已经用GlobalKey尝试过,但是收到错误消息“多个小部件使用了相同的GlobalKey。”

这是我的注册屏幕代码:

class RegistrationScreen extends StatefulWidget {
  @override
  _RegistrationScreenState createState() => _RegistrationScreenState();
}

class _RegistrationScreenState extends State<RegistrationScreen> {
  String email;
  String password;

  final formKey = GlobalKey<FormState>();

  void handleRegisterEmail(){
    if (formKey.currentState.validate()){
      print('Handling Register');
    }
  }
  void handleEmailChanged(String value) {
    setState(() {
      email = value;
    });
  }

  void handlePasswordChanged(String value) {
    setState(() {
      password = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    body: Column(
    children: <Widget>[
        AuthTextField(
          key: formKey,
          type: 'Email',
          onChanged: handleEmailChanged,
        ),
        AuthTextField(
          key: formKey
          type: 'Password',
          onChanged: handlePasswordChanged,
        ),
        AuthButton(
          text: 'Register',
          onPressed: handleRegisterEmail,
        ),
      ]
    ),
    );
  }
  
  
  }

这是AuthTextField的代码:

class AuthTextField extends StatefulWidget {
  final String emailOrPassword;
  final Function onChanged;
  final GlobalKey<FormState> key;        //Here passing the key
  AuthTextField({this.onChanged, this.emailOrPassword, this.key})
      : super(key: key);

  @override
  _AuthTextFieldState createState() => _AuthTextFieldState();
}

class _AuthTextFieldState extends State<AuthTextField> {

  String validateForm(String value) {                  //two different validators
    if (widget.emailOrPassword == 'Email') {
      validateFormEmail(value);
    } else {
      validateFormPassword(value);
    }
  }

  String validateFormEmail(String value) {
    if (!RegExp(
            r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
        .hasMatch(value)) {
      return 'Please enter a valid email address';
    }
    return null;
  }

  String validateFormPassword(String value) {
    if (value.length < 6) {
      return 'Password must be at least 6 characters.';
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 30.0),
      child: TextFormField(
        key: widget.key,                        //Passing the key
        validator: validateForm,
        keyboardType: (widget.emailOrPassword == 'Email')
            ? TextInputType.emailAddress
            : TextInputType.text,
        onChanged: widget.onChanged,
        //plus some more styling
        ),
      ),
    );
  }
}

正如我所说,我得到了错误消息。有什么建议如何解决这个问题?我尝试了很多不同的方法(例如,将RegistrationScreen中的列包装为表单,并将密钥仅传递给该表单),但是没有任何效果。

1 个答案:

答案 0 :(得分:0)

这里的问题是您正在设置 keyAuthTextField,而不是将其作为单独的字段存储在对象中。这是将其设置为 AuthTextFieldForm 对象的键。

这是您想要做的:

class AuthTextField extends StatefulWidget {
  final String emailOrPassword;
  final Function onChanged;
  final GlobalKey<FormState> formKey;        //Here passing the key
  AuthTextField({Key key, this.onChanged, this.emailOrPassword, this.formKey})
      : super(key: key);

  @override
  _AuthTextFieldState createState() => _AuthTextFieldState();
}

class _AuthTextFieldState extends State<AuthTextField> {

  String validateForm(String value) {                  //two different validators
    if (widget.emailOrPassword == 'Email') {
      validateFormEmail(value);
    } else {
      validateFormPassword(value);
    }
  }

  String validateFormEmail(String value) {
    if (!RegExp(
            r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
        .hasMatch(value)) {
      return 'Please enter a valid email address';
    }
    return null;
  }

  String validateFormPassword(String value) {
    if (value.length < 6) {
      return 'Password must be at least 6 characters.';
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 30.0),
      child: TextFormField(
        //key: widget.key, //Don't pass the key to the TextFormField only the form
        validator: validateForm,
        keyboardType: (widget.emailOrPassword == 'Email')
            ? TextInputType.emailAddress
            : TextInputType.text,
        onChanged: widget.onChanged,
        //plus some more styling
        ),
      ),
    );
  }
}

然后您需要将您的小部件包装在一个 Form 小部件中:

class RegistrationScreen extends StatefulWidget {
  @override
  _RegistrationScreenState createState() => _RegistrationScreenState();
}

class _RegistrationScreenState extends State<RegistrationScreen> {
  String email;
  String password;

  final formKey = GlobalKey<FormState>();

  void handleRegisterEmail(){
    if (formKey.currentState.validate()){
      print('Handling Register');
    }
  }
  void handleEmailChanged(String value) {
    setState(() {
      email = value;
    });
  }

  void handlePasswordChanged(String value) {
    setState(() {
      password = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    body: Form(
        key: formKey, //Wrap your column in this form widget and set the key
        child: Column(
          children: <Widget>[
            AuthTextField(
              key: formKey,
              type: 'Email',
              onChanged: handleEmailChanged,
            ),
            AuthTextField(
              key: formKey
              type: 'Password',
              onChanged: handlePasswordChanged,
            ),
            AuthButton(
              text: 'Register',
              onPressed: handleRegisterEmail,
            ),
          ]
        ),
      ),
    );
   }

   }