You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter登录页表单验证错误提示不生效、点击后自动跳转问题

Flutter登录表单错误提示及校验跳转问题修复方案

存在的问题

  • removeError方法逻辑反向:当前判断条件为!errors.contains(error)时才执行移除,应该改为存在对应错误时才移除
  • onChanged判断逻辑错误:使用else if分支,满足第一个条件后不会执行后续错误移除判断,需改为独立if判断
  • 校验规则错误:
    • 密码校验误用邮箱正则表达式判断长度,应直接判断密码长度是否小于8位
    • 邮箱校验通过后返回了非空的value,不符合validator校验通过需返回null的规则
    • 校验不通过时返回了空字符串,会导致输入框默认展示空的错误提示
  • 跳转逻辑未做校验拦截:跳转代码未放在校验通过的判断分支内,导致无论是否校验通过都会触发跳转
  • 错误列表未前置清空:每次触发校验前未清空历史错误,会导致错误重复累加残留

修复后的核心代码

登录表单代码

class sign_in_form extends StatefulWidget {
  const sign_in_form({Key? key}) : super(key: key);

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

class _sign_in_formState extends State<sign_in_form> {
  final _formKey = GlobalKey<FormState>();
  String? email;
  String? password;

  final List<String?> errors = [];

  void addError ({String? error}) {
    if (!errors.contains(error)) {
      setState(() {
        errors.add(error);
      });
    }
  }

  void removeError ({String? error}) {
    // 修复:错误存在时才移除
    if (errors.contains(error)) {
      setState(() {
        errors.remove(error);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
          buildEmailFormField(),
          SizedBox(height: getProportionateScreenHeight(20)),
          buildPasswordFormField(),
          SizedBox(height: getProportionateScreenHeight(20)),
          errors_form(errors: errors),
          SizedBox(height: getProportionateScreenHeight(20)),
          splash_button(
            press: () {
              // 修复:校验前先清空历史错误
              setState(() {
                errors.clear();
              });
              if (_formKey.currentState!.validate()) {
                _formKey.currentState!.save();
                // 修复:跳转逻辑放在此处,校验通过才执行跳转
                // 你的页面跳转代码写在这里
              }
            },
          ),
        ],
      ),
    );
  }
  TextFormField buildEmailFormField() {
    return TextFormField(
      keyboardType: TextInputType.emailAddress,
      onSaved: (newValue) => email = newValue,
      onChanged: (value) {
        // 修复:改为独立if判断,避免分支拦截
        if (value.isNotEmpty) {
          removeError(error: "Please Enter your email");
        }
        if (emailValidatorRegExp.hasMatch(value)) {
          removeError(error: "Please Enter Valid Email");
        }
        return;
      },
      validator: (value) {
        if (value!.isEmpty) {
          addError(error: "Please Enter your email");
          return null;
        }
        else if (!emailValidatorRegExp.hasMatch(value)) {
          addError(error: "Please Enter Valid Email");
          return null;
        }
        // 修复:校验通过返回null
        return null;
      },
      // 隐藏系统自带的错误提示,避免和自定义错误提示重复
      decoration: const InputDecoration(
        labelText: "Email",
        hintText: "Enter your email",
        floatingLabelBehavior: FloatingLabelBehavior.always,
        suffixIcon: Padding(
          padding: EdgeInsets.fromLTRB(0, 20, 20, 20),
          child: Icon(Icons.email),
        ),
        errorStyle: TextStyle(height: 0),
      ),
    );
  }
  TextFormField buildPasswordFormField() {
    return TextFormField(
      obscureText: true,
      onSaved: (newValue) => password = newValue,
      onChanged: (value){
        // 修复:改为独立if判断
        if (value.isNotEmpty) {
          removeError(error: "Please Enter your password");
        }
        if (value.length >= 8) {
          removeError(error: "Password is too short");
        }
        return;
      },
      validator: (value){
        if (value!.isEmpty) {
          addError(error: "Please Enter your password");
          return null;
        }
        // 修复:改为判断密码长度,不再误用邮箱正则
        else if (value.length < 8) {
          addError(error: "Password is too short");
          return null;
        }
        return null;
      },
      decoration: const InputDecoration(
        labelText: "Password",
        hintText: "Enter your password",
        floatingLabelBehavior: FloatingLabelBehavior.always,
        suffixIcon: Padding(
          padding: EdgeInsets.fromLTRB(0, 20, 20, 20),
          child: Icon(Icons.lock),
        ),
        errorStyle: TextStyle(height: 0),
      ),
    );
  }
}

错误提示表单代码无逻辑问题,可保持原样

class errors_form extends StatelessWidget {
  const errors_form({Key? key, required this.errors,}) : super(key: key);
  final List<String?> errors;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: List.generate(
          errors.length, (index) => form_error_text(errors: errors[index]!)),
    );
  }
  Row form_error_text ({required String errors}) {
    return Row(
      children: [
        SvgPicture.asset(
          "assets/icons/Error.svg",
          height: getProportionateScreenWidth(14),
          width: getProportionateScreenWidth(14),
        ),
        SizedBox(width: getProportionateScreenWidth(14)),
        Text(errors),
      ],
    );
  }
}

内容的提问来源于stack exchange,提问作者Lyana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 21:15:05