【问题标题】:Flutter Form validation with null safety具有空安全性的 Flutter 表单验证
【发布时间】:2021-06-26 08:11:13
【问题描述】:

TextFormField validate 参数接受一个函数,如果字段内容有效则返回 null,如果内容无效则返回字符串。 我的颤振项目中有 null 安全性,我无法从我的 validate 函数中返回 null。 如何编写一个有效的验证函数,并启用 null 安全性?

AppWidget.buildUserInput(
     hint: 'Referral code',
     borderRadius: BorderRadius.circular(5),
     prefixIcon: Icon(Icons.local_offer_outlined),
     onSaved: (val) => model.save(
     CreateAccountViewModel.REFERRAL_CODE, val!),
     validate: (val) {
         return null; // The return type 'Null' isn't a 'String', as required by the 
                       //closure's context
         },
      ),

这是 buildUser 输入代码


static Widget buildUserInput(
      {String? hint,
      String? labelText,
      TextAlign textAlign = TextAlign.start,
      required Function(String? val) onSaved,
      Function(String val)? onChanged,
      required String Function(String val) validate,
      TextInputType? keyboardType,
      BorderRadius borderRadius = BorderRadius.zero,
      TextEditingController? controller,
      String? initialValue,
      Widget? suffixIcon,
      Widget? prefixIcon,
      String? prefixText,
      bool hasBorder = true,
      Widget? prefix,
      bool filled = false,
      Color? fillColor,
      Color? enabledBorderColor,
      Color? focusedBorderColor,
      TextStyle? style,
      bool obscureText = false}) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 9),
      child: TextFormField(
        initialValue: initialValue,
        controller: controller,
        onSaved: onSaved,
        onChanged: onChanged,
        validator: validate,
        keyboardType: keyboardType,
        obscureText: obscureText,
        textAlign: textAlign,
        style: style ?? TextStyle(),
        decoration: InputDecoration(
          filled: filled,
          fillColor: fillColor,
          prefixText: prefixText, prefix: prefix,
          prefixStyle: TextStyle(color: AppColors.appGreen),
          suffixIcon: suffixIcon,
          prefixIcon: prefixIcon,
          hintText: hint,
          labelText: labelText,
          labelStyle: userInputStyle(),
          hintStyle: userInputStyle(),
          // filled: true,
          // fillColor: AppColors.textColor2.withOpacity(.05),
          border: hasBorder
              ? borderRadius != null
                  ? OutlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: enabledBorderColor ?? AppColors.appGreen,
                          width: 1))
                  : UnderlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: enabledBorderColor ?? AppColors.appGreen,
                          width: 1))
              : InputBorder.none,
          focusedBorder: hasBorder
              ? borderRadius != null
                  ? OutlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: focusedBorderColor ?? AppColors.appGreen,
                          width: 1))
                  : UnderlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: focusedBorderColor ?? AppColors.appGreen,
                          width: 1))
              : InputBorder.none,
          enabledBorder: hasBorder
              ? borderRadius != null
                  ? OutlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: enabledBorderColor ?? AppColors.appGreen,
                          width: 1))
                  : UnderlineInputBorder(
                      borderRadius: borderRadius,
                      borderSide: BorderSide(
                          style: BorderStyle.solid,
                          color: enabledBorderColor ?? AppColors.appGreen,
                          width: 1))
              : InputBorder.none,
        ),
      ),
    );
  }
}

【问题讨论】:

  • 什么是AppWidget.buildUserInput?其validate 参数应固定为匹配TextFormFieldvalidator
  • AppWidget.buildUserInput 是一个自定义小部件,它包装了 TextFormField 并公开了相同的参数
  • 正如我提到的,修复AppWidget.buildUserInput。目前其validate 参数与TextFormFieldvalidator 的类型不匹配。

标签: flutter dart


【解决方案1】:

我找到了解决方案,我将我的自定义验证函数的返回类型设置为 null,这样我就可以返回 null。谢谢各位。

static Widget buildUserInput(
      {String? hint,
      String? labelText,
      TextAlign textAlign = TextAlign.start,
      required Function(String? val) onSaved,
      Function(String val)? onChanged,
      required String? Function(String? val)? validate,
      TextInputType? keyboardType,
      BorderRadius borderRadius = BorderRadius.zero,
      TextEditingController? controller,
      String? initialValue,
      Widget? suffixIcon,
      ...

【讨论】:

    【解决方案2】:

    这是一个我一直在努力解决的问题,所以我希望我能帮助一些人。 在我将项目迁移到空安全后,我收到了这个错误:

    错误:无法分配参数类型“字符串函数(字符串)” 到参数类型'String?函数(字符串?)?'

    这意味着我的函数应该返回一个可以为空的字符串,并且参数也应该可以为空。

    所以我声明了我的验证器函数如下:

    String? Function(String? val)? validator;
    

    下面是我创建的函数示例:

        String? validateFirstName(String? value) {
          if (!value!.isAlphabet() || value.length > 10) {
            return 'Please enter a valid First Name';
          }
        // This code no longer needed 
        // else{
       //   return null;
       // }
    
        }
    

    对于那些试图弄清楚全貌的人,我会发布完整的代码。

    这是我创建的自定义 TextFeild:

    import './app/components/text_view.dart';
    import './app/utils/constants.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_screenutil/flutter_screenutil.dart';
    
    class EditText extends StatelessWidget {
      // final EditTextStyle editTextStyle;
      final String hintText;
      final Color colors;
      final FontWeight fontWeight;
      final double? fontSize;
      final TextAlign textAlign;
      final int maxLines;
      final double lineSpace;
      final double marginLeft,marginRight,marginTop,marginBottom;
      final double paddingLeft,paddingRight,paddingTop,paddingBottom;
      final TextDecoration decoration;
      String? Function(String? val)? validator;
      String? error;
      FocusNode focusNode =  FocusNode();
      TextEditingController? textController;
    
      EditText({
        this.colors = const Color(0xffA9A9B4),
        this.fontWeight = FontWeight.w600,
        this.fontSize,this.error,
        this.marginTop =0.0,this.marginRight = 0.0,this.marginLeft = 0.0,this.marginBottom =0.0,
        this.paddingTop =0.0,this.paddingRight = 0.0,this.paddingLeft = 0.0,this.paddingBottom =0.0,
        this.textAlign = TextAlign.start,this.validator,
        this.decoration = TextDecoration.none,this.maxLines = 1,this.lineSpace = 0.5, required this.hintText, this.textController
      });
    
      @override
      Widget build(BuildContext context) {
        return Container(
          height: 54.h,
          margin: EdgeInsets.only(left: marginLeft,right: marginRight,top: marginTop,bottom: marginBottom),
          child: TextFormField(
            textAlign: textAlign,
            maxLines: maxLines,
            focusNode: focusNode,
            controller: textController,
            validator: validator,
            decoration: InputDecoration(
                errorText: error,
                labelStyle: TextStyle(color: Colors.redAccent),
                focusedBorder: OutlineInputBorder(borderSide: BorderSide(width: 1,color: secondaryColor),
                  borderRadius: BorderRadius.circular(10.sp),),
                // border: OutlineInputBorder(borderSide: BorderSide(width: 1,color: Colors.red),
                //     borderRadius: BorderRadius.circular(10.sp),
                // ) ,
                enabledBorder: OutlineInputBorder(borderSide: BorderSide(width: 1.5,color: Color(0xffA9A9B4).withOpacity(0.5)),
                  borderRadius: BorderRadius.circular(10.sp),
                ),
                label: TextView(text: hintText,colors: focusNode.hasFocus ? secondaryColor : colors,fontSize: 16.sp,textViewStyle: TextViewStyle.THIN,)
            ),
            // overflow: TextOverflow.ellipsis,
            style: FontStyles.montserratSemiBold.copyWith(
                color: colors,
                fontWeight: FontWeight.w600,
                fontSize: fontSize ?? 16.sp,
                decoration: decoration,letterSpacing: lineSpace
            ),
          ),
        );
      }
    }
    

    这是验证器类:

    import 'package:regexpattern/regexpattern.dart';
    
    String? validateEmail(String? value) {
      // Pattern pattern =
      //     r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+";
      // RegExp regex = new RegExp(pattern);
      if (!value!.isEmail()) {
        return 'Please enter a valid Email';
      }
    }
    
    String? validateLoginPassword(String? value) {
      if(value!.length < 6){
        return 'Invalid password';
      }
      else {
        return null;
      }
    }
    
    String? validatePassword(String? value) {
      if(value!.length < 6){
        return 'Invalid password, length must be more than 6';
      }
    
    }
    
    
    String? validateFirstName(String? value) {
      if (!value!.isAlphabet() || value.length > 10) {
        return 'Please enter a valid First Name';
      }
    }
    
    String? validateLastName(String value) {
      if (!value.isAlphabet() || value.length > 10) {
        return 'Please enter a valid Last Name';
      } else {
        return null;
      }
    }
    
    String? validateMobileNumber(String? value) {
      // Pattern pattern =
      //     r'^{0-9}$';
      // RegExp regex = new RegExp(pattern);
      // if(value.length <7 || value.length > 14){
      //   return 'Invalid Number';
      // }
      // else
        if(value!.length <7 || value.length > 14){
            return 'Invalid phone Number';
        }
      }
    
    
    String? validateOTP(String? value) {
      if (value!.length < 4 ) {
        return 'Please enter a valid OTP';
      }
    }
    //Please enter a valid Mobile No
    

    这是我如何使用这些 textFeilds 之一

         EditText(hintText:"Name",fontSize: 12.sp,paddingLeft: 8,marginLeft:  10.h,marginRight: 10.h ,
    textController: controller.nameController,validator: validateFirstName)
    

    【讨论】:

      【解决方案3】:

      问题不清楚。所以如果你想使用 Flutter Form()。您需要一个表单键 = GlobalKey()。如果你想在无效时得到警告你不能返回''。当您的值无效时,它会发出红色警告。

         Form(
            key: GlobalKey<FormState>()
            child: TextFormField(
              validator: (value) {
                if (value invalid) {
                  return '';
                }
                return null;
              },
            ),
          )
      

      【讨论】:

      • 无法从方法“validateField”返回“Null”类型的值,因为它的返回类型为“String”
      【解决方案4】:

      您可以按照此示例解决您的问题。 假设这是我用于电子邮件验证的 TextFormField:-

                TextFormField(
                decoration: InputDecoration(
                    labelText: 'EMAIL',
                    labelStyle: TextStyle(
                        fontFamily: 'Trueno',
                        fontSize: 12.0,
                        color: Colors.grey.withOpacity(0.5)),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: greenColor),
                    )),
                onChanged: (value) {
                  this.email = value;
                },
                validator: (value) =>
                    value!.isEmpty ? 'Email is required' : validateEmail(value))
      

      这是我的电子邮件验证方法:-

        String? validateEmail(String value) {
      RegExp regex = RegExp(some regex pattern);
      if (!regex.hasMatch(value))
        return 'Enter Valid Email';
      else
        return null; }
      

      要在返回 null 时修复错误,我们必须将 validateEmail(String value) 方法的返回类型设置为可为空。即 String? >

      【讨论】:

      • 无法从方法“validateField”返回“Null”类型的值,因为它的返回类型为“String”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多