如何基于验证器动态更改textformfield中errorstyle的颜色?

How to dynamically change colour of errorstyle in textformfield based on validator?

我有一个 TextFormField 使用验证器检查输入是否满足一组要求。如果输入不满足特定要求,red 中的错误文本将相应地通知用户。如果密码满足所有要求,我想 return green 文本(“安全密码”)。

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

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

class _RegFormState extends State<RegForm> {
  Color errorClr = Colors.red;
  final String checkAll =
                r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#$&*~]).{8,}$';
  final String checkLetters = r'^(?=.*?[A-Z])(?=.*?[a-z])';
  final String checkNumbers = r'^(?=.*?[0-9])';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextFormField(
        autovalidateMode: AutovalidateMode.onUserInteraction,
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Please enter a valid password';
          } else {
            if (value.length < 8)
              return 'Password has to be 8 characters or more!';
            else if (!RegExp(checkLetters).hasMatch(value))
              return 'Password has to contain Uppercase and Lowercase letters!';
            else if (!RegExp(checkNumbers).hasMatch(value))
              return 'Password has to contain numbers!';
            else if (RegExp(checkAll).hasMatch(value)) {
              errorClr = Colors.green;
              return 'Very secure password!';
            }
          }
          errorClr = Colors.green;
          return 'Secure password!';
        },
        decoration: InputDecoration(
          errorStyle: TextStyle(
            color: errorClr,
          ),
          contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
          hintText:
              'Password must be at least 8 characters long, contains numbers and both upper and lowercase letters',
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(10.0),
          ),
        ),
      ),
    );
  }
}

上面的代码不会 return 绿色的“安全密码”文本,我认为这是因为验证程序不会重建小部件,因此 errorStyle 不会更新。有没有办法让这个工作?

您不能从验证程序函数内部调用 setState(),这是您需要更改 errorClr 或成功文本的地方。另外验证器函数需要returnnull来表示验证通过;所以你不能简单地 return 安全密码!.

你觉得用helperText输出成功信息怎么样

If non-null, the text is displayed below the InputDecorator.child, in the same location as errorText. If a non-null errorText value is specified then the helper text is not shown.

定义一个指示密码是否有效的新变量(默认值:false):

bool validPassword = false;

使用onChanged检查密码是否有效:

onChanged: (String value) {
  if (RegExp(checkAll).hasMatch(value))
    setState(() {
      validPassword = true;
    });
  },

helperTexthelperStyle 添加到您的 InputDecoration:

 helperText: validPassword ? 'Secure Password' : null,
 helperStyle: TextStyle(color: Colors.green),

完整示例:

class _RegFormState extends State<RegForm> {
  final String checkAll = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#$&*~]).{8,}$';
  final String checkSpecial = r'^(?=.*?[!@#$&*~])';
  final String checkLetters = r'^(?=.*?[A-Z])(?=.*?[a-z])';
  final String checkNumbers = r'^(?=.*?[0-9])';

  bool validPassword = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextFormField(
        autovalidateMode: AutovalidateMode.onUserInteraction,
          validator: (value) {
            if (value == null || value.isEmpty || value.trim().length < 8) // use trim() for the whitrespaces
              return 'Password has to be 8 characters or more!';

            if (!RegExp(checkLetters).hasMatch(value))
              return 'Password has to contain Uppercase and Lowercase letters!';

            if (!RegExp(checkNumbers).hasMatch(value))
              return 'Password has to contain numbers!';

            if (!RegExp(checkSpecial).hasMatch(value))
              return 'Password has to contain a special character!';

            return null; // to indicate a success
         },
         onChanged: (String value) {
           if (RegExp(checkAll).hasMatch(value))
             setState(() {
               validPassword = true;
             });
           },
        decoration: InputDecoration(
          contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
          helperText: validPassword ? 'Secure Password' : null,
          helperStyle: TextStyle(color: Colors.green),
          hintText:
          'Password must be at least 8 characters long, contains numbers and both upper and lowercase letters',
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(10.0),
         ),
        ),
      ),
    );
  }