具有空安全性的颤动表单验证器

flutter form validator with null safety

我在尝试在我的登录屏幕上制作表单验证器时遇到问题,当我磁带登录并且文本字段已经为空时它不起作用。如果您有任何帮助,这是我的代码,我想: TextFormField 验证参数采用一个函数,如果字段内容有效,则 return 为空,如果内容无效,则为字符串。我的 flutter 项目中有 null 安全性,我的验证函数不能 return null。我如何编写一个启用空安全的有效验证函数?

登录代码屏幕:

import 'package:flutter/material.dart';
import 'package:flutter_udemy/shared/components/components.dart';

class LoginScreen extends StatefulWidget {
LoginScreen({Key? key}) : super(key: key);
@override
_LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
var emailController = TextEditingController();
var passwordController = TextEditingController();
var formKey = GlobalKey<FormState>();
bool isPassword = true;

@override
Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(),
  body: Padding(
    padding: const EdgeInsets.all(20.0),
    child: Center(
      child: SingleChildScrollView(
        child: Form(
          key: formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Login',
                style: TextStyle(
                  fontSize: 40.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
              SizedBox(
                height: 40.0,
              ),
              defaultFormField(
                controller: emailController,
                label: 'Email',
                prefix: Icons.email,
                type: TextInputType.emailAddress,
                validate: (String value) {
                  if (value.isEmpty) {
                    return 'email must not be empty';
                  }

                  return null;
                },
              ),
              SizedBox(
                height: 15.0,
              ),
              defaultFormField(
                controller: passwordController,
                label: 'Password',
                prefix: Icons.lock,
                suffix:
                    isPassword ? Icons.visibility : Icons.visibility_off,
                isPassword: isPassword,
                suffixPressed: () {
                  setState(() {
                    isPassword = !isPassword;
                  });
                },
                type: TextInputType.visiblePassword,
                validate: (String value) {
                  if (value.isEmpty) {
                    return 'password is too short';
                  }
                  return null;
                },
              ),
              SizedBox(
                height: 20.0,
              ),
              defaultButton(
                text: 'login',
                function: () {
                  if (formKey.currentState!.validate()) {
                    print(emailController.text);
                    print(passwordController.text);
                  }
                },
              ),
              SizedBox(
                height: 20.0,
              ),
              defaultButton(
                text: 'ReGIster',
                function: () {
                  print(emailController.text);
                  print(passwordController.text);
                },
              ),
              SizedBox(
                height: 10.0,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Don\'t have an account?',
                  ),
                  TextButton(
                    onPressed: () {},
                    child: Text(
                      'Register Now',
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
     ),
    ),
   );
   }
  }

我得到按钮小部件和文本字段小部件的组件代码屏幕:

 import 'package:flutter/material.dart';

   Widget defaultButton({
  double width = double.infinity,
  Color background = Colors.blue,
  bool isUpperCase = true,
  double radius = 10.0,
   required Function function,
    required String text,
   }) =>
       Container(
       width: width,
       height: 50.0,
        child: MaterialButton(
        onPressed: () {
       function();
     },
     child: Text(
      isUpperCase ? text.toUpperCase() : text,
      style: TextStyle(
        color: Colors.white,
      ),
    ),
  ),
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(
      radius,
    ),
    color: background,
  ),
);

   Widget defaultFormField({
  required TextEditingController controller,
  required TextInputType type,
  Function? onSubmit,
   Function? onChange,
     bool isPassword = false,
   required Function validate,
   required String label,
   required IconData prefix,
   IconData? suffix,
   Function? suffixPressed,
     }) =>
    TextFormField(
     controller: controller,
    keyboardType: type,
    obscureText: isPassword,
    onFieldSubmitted: (s) {
      onSubmit!(s);
    },
  onChanged: (s) {
    onChange!(s);
  },
  validator: (s) {
    validate(s);
  },
  decoration: InputDecoration(
    labelText: label,
    prefixIcon: Icon(
      prefix,
    ),
    suffixIcon: suffix != null
        ? IconButton(
            onPressed: () {
              suffixPressed!();
            },
            icon: Icon(
              suffix,
            ),
          )
        : null,
    border: OutlineInputBorder(),
  ),
);

此代码有效
为零安全所做的主要更改
需要字符串吗?函数(字符串?)?验证

validate: (String? value) {
   if (value!.isEmpty) 
   {
        return 'email must not be empty';
   }
       return null;
   },

完整代码如下

class LoginScreen extends StatefulWidget {
LoginScreen({Key? key}) : super(key: key);
@override
_LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
var emailController = TextEditingController();
var passwordController = TextEditingController();
final formKey = GlobalKey<FormState>();
bool isPassword = true;

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(),
    body: Padding(
    padding: const EdgeInsets.all(20.0),
    child: Center(
      child: SingleChildScrollView(
        child: Form(
          key: formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Login',
                style: TextStyle(
                  fontSize: 40.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
              SizedBox(
                height: 40.0,
              ),
              defaultFormField(
                controller: emailController,
                label: 'Email',
                prefix: Icons.email,
                type: TextInputType.emailAddress,
                validate: (String? value) {
                  if (value!.isEmpty) {
                    return 'email must not be empty';
                  }

                  return null;
                },
              ),
              SizedBox(
                height: 15.0,
              ),
              defaultFormField(
                controller: passwordController,
                label: 'Password',
                prefix: Icons.lock,
                suffix:
                    isPassword ? Icons.visibility : Icons.visibility_off,
                isPassword: isPassword,
                suffixPressed: () {
                  setState(() {
                    isPassword = !isPassword;
                  });
                },
                type: TextInputType.visiblePassword,
                validate: (String? value) {
                  if (value!.isEmpty) {
                    return 'password is too short';
                  }
                  return null;
                },
              ),
              SizedBox(
                height: 20.0,
              ),
              defaultButton(
                text: 'login',
                function: () {
                  if (formKey.currentState!.validate()) {
                    print(emailController.text);
                    print(passwordController.text);
                  }
                },
              ),
              SizedBox(
                height: 20.0,
              ),
              defaultButton(
                text: 'ReGIster',
                function: () {
                  print(emailController.text);
                  print(passwordController.text);
                },
              ),
              SizedBox(
                height: 10.0,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Don\'t have an account?',
                  ),
                  TextButton(
                    onPressed: () {},
                    child: Text(
                      'Register Now',
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    ),
  ),
);
}

Widget defaultButton({
double width = double.infinity,
Color background = Colors.blue,
bool isUpperCase = true,
double radius = 10.0,
required Function function,
required String text,
}) =>
  Container(
    width: width,
    height: 50.0,
    child: MaterialButton(
      onPressed: () {
        function();
      },
      child: Text(
        isUpperCase ? text.toUpperCase() : text,
        style: TextStyle(
          color: Colors.white,
        ),
      ),
    ),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(
        radius,
      ),
      color: background,
    ),
  );
}

Widget defaultFormField({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit,
Function? onChange,
bool isPassword = false,
required String? Function(String?)? validate,
required String label,
required IconData prefix,
IconData? suffix,
Function? suffixPressed,
}) =>
  TextFormField(
    controller: controller,
    keyboardType: type,
    obscureText: isPassword,
    onFieldSubmitted: (s) {
      onSubmit!(s);
    },
    onChanged: (s) {
      onChange!(s);
    },
    validator: validate,
    decoration: InputDecoration(
      labelText: label,
      prefixIcon: Icon(
        prefix,
      ),
      suffixIcon: suffix != null
          ? IconButton(
              onPressed: () {
                suffixPressed!();
              },
              icon: Icon(
                suffix,
              ),
            )
          : null,
      border: OutlineInputBorder(),
    ),
  );

你可以试试这个

validate: (String? value) { 
if (value == null || value.trim().isEmpty) {
  return 'Please provide a value.';
}
return null;
}