Flutter表单处理与验证完全指南引言表单是移动应用中最常见的交互元素之一用于收集用户输入并进行验证。Flutter提供了强大的表单处理能力从基础的TextField到复杂的表单验证都有很好的支持。本文将深入探讨Flutter表单处理的各种技术和最佳实践。基础表单组件TextField组件TextField( decoration: InputDecoration( labelText: 用户名, hintText: 请输入用户名, prefixIcon: const Icon(Icons.person), border: const OutlineInputBorder(), ), keyboardType: TextInputType.text, textInputAction: TextInputAction.next, onChanged: (value) { // 实时处理输入 print(输入: $value); }, onSubmitted: (value) { // 提交时处理 print(提交: $value); }, )TextFormField组件TextFormField是带有验证功能的TextFieldTextFormField( decoration: const InputDecoration( labelText: 邮箱, hintText: 请输入邮箱地址, ), validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱地址; } return null; }, )Form组件Form组件用于管理一组表单字段final _formKey GlobalKeyFormState(); Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( children: [ TextFormField( decoration: const InputDecoration(labelText: 用户名), validator: (value) { if (value null || value.isEmpty) { return 请输入用户名; } return null; }, ), const SizedBox(height: 16), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { // 表单验证通过 print(表单验证通过); } }, child: const Text(提交), ), ], ), )表单验证内置验证器TextFormField( // 必填验证 validator: (value) { if (value null || value.isEmpty) { return 此字段必填; } return null; }, ) TextFormField( // 最小长度验证 validator: (value) { if (value null || value.length 6) { return 最少需要6个字符; } return null; }, ) TextFormField( // 最大长度验证 validator: (value) { if (value ! null value.length 50) { return 最多允许50个字符; } return null; }, )正则表达式验证// 邮箱验证 final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); TextFormField( validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱地址; } return null; }, ) // 手机号码验证 final phoneRegex RegExp(r^1[3-9]\d{9}$); TextFormField( keyboardType: TextInputType.phone, validator: (value) { if (value null || value.isEmpty) { return 请输入手机号; } if (!phoneRegex.hasMatch(value)) { return 请输入有效的手机号; } return null; }, ) // URL验证 final urlRegex RegExp(rhttps?:\/\/[\w-](\.[\w-])([\w.,?^%:/~#-]*[\w?^%/~#-])?); TextFormField( validator: (value) { if (value null || value.isEmpty) { return 请输入URL; } if (!urlRegex.hasMatch(value)) { return 请输入有效的URL; } return null; }, )自定义验证器class PasswordValidator { static String? validate(String? value) { if (value null || value.isEmpty) { return 请输入密码; } // 检查长度 if (value.length 8) { return 密码至少需要8个字符; } // 检查是否包含数字 if (!value.contains(RegExp(r\d))) { return 密码必须包含至少一个数字; } // 检查是否包含字母 if (!value.contains(RegExp(r[a-zA-Z]))) { return 密码必须包含至少一个字母; } // 检查是否包含特殊字符 if (!value.contains(RegExp(r[!#$%^*(),.?:{}|]))) { return 密码必须包含至少一个特殊字符; } return null; } } // 使用自定义验证器 TextFormField( obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: PasswordValidator.validate, )表单状态管理使用StatefulWidget管理状态class LoginForm extends StatefulWidget { const LoginForm({super.key}); override StateLoginForm createState() _LoginFormState(); } class _LoginFormState extends StateLoginForm { final _formKey GlobalKeyFormState(); String _email ; String _password ; void _submitForm() { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); // 处理表单数据 print(邮箱: $_email, 密码: $_password); } } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( decoration: const InputDecoration(labelText: 邮箱), validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } return null; }, onSaved: (value) { _email value ?? ; }, ), TextFormField( obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } return null; }, onSaved: (value) { _password value ?? ; }, ), ElevatedButton( onPressed: _submitForm, child: const Text(登录), ), ], ), ); } }使用TextEditingControllerclass MyForm extends StatefulWidget { const MyForm({super.key}); override StateMyForm createState() _MyFormState(); } class _MyFormState extends StateMyForm { final _emailController TextEditingController(); final _passwordController TextEditingController(); override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } void _submit() { final email _emailController.text; final password _passwordController.text; print(邮箱: $email, 密码: $password); } override Widget build(BuildContext context) { return Column( children: [ TextField( controller: _emailController, decoration: const InputDecoration(labelText: 邮箱), ), TextField( controller: _passwordController, obscureText: true, decoration: const InputDecoration(labelText: 密码), ), ElevatedButton( onPressed: _submit, child: const Text(提交), ), ], ); } }高级表单功能表单联动验证class PasswordForm extends StatefulWidget { const PasswordForm({super.key}); override StatePasswordForm createState() _PasswordFormState(); } class _PasswordFormState extends StatePasswordForm { final _formKey GlobalKeyFormState(); final _passwordController TextEditingController(); final _confirmController TextEditingController(); override void dispose() { _passwordController.dispose(); _confirmController.dispose(); super.dispose(); } String? _validateConfirmPassword(String? value) { if (value null || value.isEmpty) { return 请再次输入密码; } if (value ! _passwordController.text) { return 两次输入的密码不一致; } return null; } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( controller: _passwordController, obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } if (value.length 8) { return 密码至少需要8个字符; } return null; }, ), TextFormField( controller: _confirmController, obscureText: true, decoration: const InputDecoration(labelText: 确认密码), validator: _validateConfirmPassword, ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { print(表单验证通过); } }, child: const Text(提交), ), ], ), ); } }动态表单字段class DynamicForm extends StatefulWidget { const DynamicForm({super.key}); override StateDynamicForm createState() _DynamicFormState(); } class _DynamicFormState extends StateDynamicForm { final _formKey GlobalKeyFormState(); final ListTextEditingController _controllers []; override void initState() { super.initState(); _controllers.add(TextEditingController()); } override void dispose() { for (var controller in _controllers) { controller.dispose(); } super.dispose(); } void _addField() { setState(() { _controllers.add(TextEditingController()); }); } void _removeField(int index) { setState(() { _controllers[index].dispose(); _controllers.removeAt(index); }); } void _submit() { if (_formKey.currentState!.validate()) { final values _controllers.map((c) c.text).toList(); print(表单值: $values); } } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ for (var i 0; i _controllers.length; i) Row( children: [ Expanded( child: TextFormField( controller: _controllers[i], decoration: InputDecoration(labelText: 字段 ${i 1}), validator: (value) { if (value null || value.isEmpty) { return 此字段必填; } return null; }, ), ), IconButton( icon: const Icon(Icons.remove), onPressed: _controllers.length 1 ? () _removeField(i) : null, ), ], ), ElevatedButton( onPressed: _addField, child: const Text(添加字段), ), ElevatedButton( onPressed: _submit, child: const Text(提交), ), ], ), ); } }异步验证class AsyncValidationForm extends StatefulWidget { const AsyncValidationForm({super.key}); override StateAsyncValidationForm createState() _AsyncValidationFormState(); } class _AsyncValidationFormState extends StateAsyncValidationForm { final _formKey GlobalKeyFormState(); final _usernameController TextEditingController(); bool _isChecking false; String? _validationError; Futurevoid _checkUsername() async { setState(() { _isChecking true; _validationError null; }); // 模拟API调用 await Future.delayed(const Duration(seconds: 1)); // 检查用户名是否已存在 final username _usernameController.text; if (username admin) { setState(() { _validationError 用户名已存在; }); } setState(() { _isChecking false; }); } override void dispose() { _usernameController.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( controller: _usernameController, decoration: InputDecoration( labelText: 用户名, errorText: _validationError, suffixIcon: _isChecking ? const CircularProgressIndicator() : null, ), onChanged: (_) _checkUsername(), ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate() !_isChecking _validationError null) { print(表单验证通过); } }, child: const Text(提交), ), ], ), ); } }表单样式定制自定义输入框样式TextField( decoration: InputDecoration( labelText: 自定义输入框, hintText: 请输入内容, labelStyle: const TextStyle( color: Colors.blue, fontSize: 16, ), hintStyle: const TextStyle( color: Colors.grey, fontSize: 14, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.grey, width: 2, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.blue, width: 2, ), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.red, width: 2, ), ), filled: true, fillColor: Colors.grey[100], contentPadding: const EdgeInsets.all(16), ), )带图标的输入框TextField( decoration: InputDecoration( labelText: 搜索, prefixIcon: const Icon(Icons.search), prefixIconColor: Colors.grey, suffixIcon: const Icon(Icons.clear), suffixIconColor: Colors.grey, border: const OutlineInputBorder(), ), )密码可见性切换class PasswordField extends StatefulWidget { const PasswordField({super.key}); override StatePasswordField createState() _PasswordFieldState(); } class _PasswordFieldState extends StatePasswordField { bool _obscureText true; override Widget build(BuildContext context) { return TextField( obscureText: _obscureText, decoration: InputDecoration( labelText: 密码, suffixIcon: IconButton( icon: Icon( _obscureText ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscureText !_obscureText; }); }, ), border: const OutlineInputBorder(), ), ); } }实战案例案例1登录表单class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); override Widget build(BuildContext context) { final emailController TextEditingController(); final passwordController TextEditingController(); return Scaffold( appBar: AppBar(title: const Text(登录)), body: Padding( padding: const EdgeInsets.all(16), child: Form( child: Column( children: [ TextFormField( controller: emailController, decoration: const InputDecoration( labelText: 邮箱, prefixIcon: Icon(Icons.email), border: OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: passwordController, decoration: const InputDecoration( labelText: 密码, prefixIcon: Icon(Icons.lock), border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } if (value.length 6) { return 密码至少6个字符; } return null; }, ), const SizedBox(height: 24), ElevatedButton( onPressed: () { // 处理登录逻辑 print(登录: ${emailController.text}); }, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text(登录), ), ], ), ), ), ); } }案例2注册表单class RegisterScreen extends StatefulWidget { const RegisterScreen({super.key}); override StateRegisterScreen createState() _RegisterScreenState(); } class _RegisterScreenState extends StateRegisterScreen { final _formKey GlobalKeyFormState(); final _emailController TextEditingController(); final _passwordController TextEditingController(); final _confirmController TextEditingController(); bool _agreed false; override void dispose() { _emailController.dispose(); _passwordController.dispose(); _confirmController.dispose(); super.dispose(); } void _submit() { if (_formKey.currentState!.validate() _agreed) { // 处理注册逻辑 print(注册成功); } else if (!_agreed) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(请同意服务条款)), ); } } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(注册)), body: Padding( padding: const EdgeInsets.all(16), child: Form( key: _formKey, child: ListView( children: [ TextFormField( controller: _emailController, decoration: const InputDecoration( labelText: 邮箱, border: OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value null || value.isEmpty) return 请输入邮箱; if (!RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$).hasMatch(value)) { return 请输入有效的邮箱; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _passwordController, decoration: const InputDecoration( labelText: 密码, border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) return 请输入密码; if (value.length 8) return 密码至少8个字符; return null; }, ), const SizedBox(height: 12), TextFormField( controller: _confirmController, decoration: const InputDecoration( labelText: 确认密码, border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) return 请再次输入密码; if (value ! _passwordController.text) return 两次密码不一致; return null; }, ), const SizedBox(height: 16), Row( children: [ Checkbox( value: _agreed, onChanged: (value) { setState(() { _agreed value ?? false; }); }, ), const Text(我已阅读并同意服务条款), ], ), const SizedBox(height: 24), ElevatedButton( onPressed: _submit, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text(注册), ), ], ), ), ), ); } }表单验证最佳实践1. 实时验证TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, // ... )2. 错误信息清晰// 好的错误信息 validator: (value) { if (value null || value.isEmpty) { return 请输入用户名; } if (value.length 3) { return 用户名至少需要3个字符; } return null; } // 避免模糊的错误信息 validator: (value) { if (value null || value.isEmpty || value.length 3) { return 输入无效; // 不好用户不知道具体哪里错了 } return null; }3. 输入限制TextField( maxLength: 50, inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r[a-zA-Z0-9])), ], )4. 键盘类型适配// 邮箱 TextField(keyboardType: TextInputType.emailAddress) // 手机号 TextField(keyboardType: TextInputType.phone) // 数字 TextField(keyboardType: TextInputType.number) // 多行文本 TextField( keyboardType: TextInputType.multiline, maxLines: null, )5. 表单焦点管理final _emailFocus FocusNode(); final _passwordFocus FocusNode(); TextField( focusNode: _emailFocus, textInputAction: TextInputAction.next, onSubmitted: (_) { FocusScope.of(context).requestFocus(_passwordFocus); }, ) TextField( focusNode: _passwordFocus, textInputAction: TextInputAction.done, onSubmitted: (_) { _passwordFocus.unfocus(); // 提交表单 }, )总结Flutter提供了强大的表单处理能力通过本文的学习你应该掌握了基础组件TextField、TextFormField、Form表单验证内置验证、正则表达式验证、自定义验证器状态管理StatefulWidget、TextEditingController高级功能表单联动、动态字段、异步验证样式定制自定义输入框样式、图标、密码可见性切换核心要点使用Form组件管理表单状态使用TextFormField进行表单验证使用TextEditingController控制输入内容使用validator函数进行验证使用GlobalKeyFormState管理表单掌握这些技能后你可以创建出功能完善、用户体验良好的表单界面。
Flutter表单处理与验证完全指南
Flutter表单处理与验证完全指南引言表单是移动应用中最常见的交互元素之一用于收集用户输入并进行验证。Flutter提供了强大的表单处理能力从基础的TextField到复杂的表单验证都有很好的支持。本文将深入探讨Flutter表单处理的各种技术和最佳实践。基础表单组件TextField组件TextField( decoration: InputDecoration( labelText: 用户名, hintText: 请输入用户名, prefixIcon: const Icon(Icons.person), border: const OutlineInputBorder(), ), keyboardType: TextInputType.text, textInputAction: TextInputAction.next, onChanged: (value) { // 实时处理输入 print(输入: $value); }, onSubmitted: (value) { // 提交时处理 print(提交: $value); }, )TextFormField组件TextFormField是带有验证功能的TextFieldTextFormField( decoration: const InputDecoration( labelText: 邮箱, hintText: 请输入邮箱地址, ), validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱地址; } return null; }, )Form组件Form组件用于管理一组表单字段final _formKey GlobalKeyFormState(); Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: Column( children: [ TextFormField( decoration: const InputDecoration(labelText: 用户名), validator: (value) { if (value null || value.isEmpty) { return 请输入用户名; } return null; }, ), const SizedBox(height: 16), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { // 表单验证通过 print(表单验证通过); } }, child: const Text(提交), ), ], ), )表单验证内置验证器TextFormField( // 必填验证 validator: (value) { if (value null || value.isEmpty) { return 此字段必填; } return null; }, ) TextFormField( // 最小长度验证 validator: (value) { if (value null || value.length 6) { return 最少需要6个字符; } return null; }, ) TextFormField( // 最大长度验证 validator: (value) { if (value ! null value.length 50) { return 最多允许50个字符; } return null; }, )正则表达式验证// 邮箱验证 final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); TextFormField( validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱地址; } return null; }, ) // 手机号码验证 final phoneRegex RegExp(r^1[3-9]\d{9}$); TextFormField( keyboardType: TextInputType.phone, validator: (value) { if (value null || value.isEmpty) { return 请输入手机号; } if (!phoneRegex.hasMatch(value)) { return 请输入有效的手机号; } return null; }, ) // URL验证 final urlRegex RegExp(rhttps?:\/\/[\w-](\.[\w-])([\w.,?^%:/~#-]*[\w?^%/~#-])?); TextFormField( validator: (value) { if (value null || value.isEmpty) { return 请输入URL; } if (!urlRegex.hasMatch(value)) { return 请输入有效的URL; } return null; }, )自定义验证器class PasswordValidator { static String? validate(String? value) { if (value null || value.isEmpty) { return 请输入密码; } // 检查长度 if (value.length 8) { return 密码至少需要8个字符; } // 检查是否包含数字 if (!value.contains(RegExp(r\d))) { return 密码必须包含至少一个数字; } // 检查是否包含字母 if (!value.contains(RegExp(r[a-zA-Z]))) { return 密码必须包含至少一个字母; } // 检查是否包含特殊字符 if (!value.contains(RegExp(r[!#$%^*(),.?:{}|]))) { return 密码必须包含至少一个特殊字符; } return null; } } // 使用自定义验证器 TextFormField( obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: PasswordValidator.validate, )表单状态管理使用StatefulWidget管理状态class LoginForm extends StatefulWidget { const LoginForm({super.key}); override StateLoginForm createState() _LoginFormState(); } class _LoginFormState extends StateLoginForm { final _formKey GlobalKeyFormState(); String _email ; String _password ; void _submitForm() { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); // 处理表单数据 print(邮箱: $_email, 密码: $_password); } } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( decoration: const InputDecoration(labelText: 邮箱), validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } return null; }, onSaved: (value) { _email value ?? ; }, ), TextFormField( obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } return null; }, onSaved: (value) { _password value ?? ; }, ), ElevatedButton( onPressed: _submitForm, child: const Text(登录), ), ], ), ); } }使用TextEditingControllerclass MyForm extends StatefulWidget { const MyForm({super.key}); override StateMyForm createState() _MyFormState(); } class _MyFormState extends StateMyForm { final _emailController TextEditingController(); final _passwordController TextEditingController(); override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } void _submit() { final email _emailController.text; final password _passwordController.text; print(邮箱: $email, 密码: $password); } override Widget build(BuildContext context) { return Column( children: [ TextField( controller: _emailController, decoration: const InputDecoration(labelText: 邮箱), ), TextField( controller: _passwordController, obscureText: true, decoration: const InputDecoration(labelText: 密码), ), ElevatedButton( onPressed: _submit, child: const Text(提交), ), ], ); } }高级表单功能表单联动验证class PasswordForm extends StatefulWidget { const PasswordForm({super.key}); override StatePasswordForm createState() _PasswordFormState(); } class _PasswordFormState extends StatePasswordForm { final _formKey GlobalKeyFormState(); final _passwordController TextEditingController(); final _confirmController TextEditingController(); override void dispose() { _passwordController.dispose(); _confirmController.dispose(); super.dispose(); } String? _validateConfirmPassword(String? value) { if (value null || value.isEmpty) { return 请再次输入密码; } if (value ! _passwordController.text) { return 两次输入的密码不一致; } return null; } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( controller: _passwordController, obscureText: true, decoration: const InputDecoration(labelText: 密码), validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } if (value.length 8) { return 密码至少需要8个字符; } return null; }, ), TextFormField( controller: _confirmController, obscureText: true, decoration: const InputDecoration(labelText: 确认密码), validator: _validateConfirmPassword, ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { print(表单验证通过); } }, child: const Text(提交), ), ], ), ); } }动态表单字段class DynamicForm extends StatefulWidget { const DynamicForm({super.key}); override StateDynamicForm createState() _DynamicFormState(); } class _DynamicFormState extends StateDynamicForm { final _formKey GlobalKeyFormState(); final ListTextEditingController _controllers []; override void initState() { super.initState(); _controllers.add(TextEditingController()); } override void dispose() { for (var controller in _controllers) { controller.dispose(); } super.dispose(); } void _addField() { setState(() { _controllers.add(TextEditingController()); }); } void _removeField(int index) { setState(() { _controllers[index].dispose(); _controllers.removeAt(index); }); } void _submit() { if (_formKey.currentState!.validate()) { final values _controllers.map((c) c.text).toList(); print(表单值: $values); } } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ for (var i 0; i _controllers.length; i) Row( children: [ Expanded( child: TextFormField( controller: _controllers[i], decoration: InputDecoration(labelText: 字段 ${i 1}), validator: (value) { if (value null || value.isEmpty) { return 此字段必填; } return null; }, ), ), IconButton( icon: const Icon(Icons.remove), onPressed: _controllers.length 1 ? () _removeField(i) : null, ), ], ), ElevatedButton( onPressed: _addField, child: const Text(添加字段), ), ElevatedButton( onPressed: _submit, child: const Text(提交), ), ], ), ); } }异步验证class AsyncValidationForm extends StatefulWidget { const AsyncValidationForm({super.key}); override StateAsyncValidationForm createState() _AsyncValidationFormState(); } class _AsyncValidationFormState extends StateAsyncValidationForm { final _formKey GlobalKeyFormState(); final _usernameController TextEditingController(); bool _isChecking false; String? _validationError; Futurevoid _checkUsername() async { setState(() { _isChecking true; _validationError null; }); // 模拟API调用 await Future.delayed(const Duration(seconds: 1)); // 检查用户名是否已存在 final username _usernameController.text; if (username admin) { setState(() { _validationError 用户名已存在; }); } setState(() { _isChecking false; }); } override void dispose() { _usernameController.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ TextFormField( controller: _usernameController, decoration: InputDecoration( labelText: 用户名, errorText: _validationError, suffixIcon: _isChecking ? const CircularProgressIndicator() : null, ), onChanged: (_) _checkUsername(), ), ElevatedButton( onPressed: () { if (_formKey.currentState!.validate() !_isChecking _validationError null) { print(表单验证通过); } }, child: const Text(提交), ), ], ), ); } }表单样式定制自定义输入框样式TextField( decoration: InputDecoration( labelText: 自定义输入框, hintText: 请输入内容, labelStyle: const TextStyle( color: Colors.blue, fontSize: 16, ), hintStyle: const TextStyle( color: Colors.grey, fontSize: 14, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.grey, width: 2, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.blue, width: 2, ), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide( color: Colors.red, width: 2, ), ), filled: true, fillColor: Colors.grey[100], contentPadding: const EdgeInsets.all(16), ), )带图标的输入框TextField( decoration: InputDecoration( labelText: 搜索, prefixIcon: const Icon(Icons.search), prefixIconColor: Colors.grey, suffixIcon: const Icon(Icons.clear), suffixIconColor: Colors.grey, border: const OutlineInputBorder(), ), )密码可见性切换class PasswordField extends StatefulWidget { const PasswordField({super.key}); override StatePasswordField createState() _PasswordFieldState(); } class _PasswordFieldState extends StatePasswordField { bool _obscureText true; override Widget build(BuildContext context) { return TextField( obscureText: _obscureText, decoration: InputDecoration( labelText: 密码, suffixIcon: IconButton( icon: Icon( _obscureText ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscureText !_obscureText; }); }, ), border: const OutlineInputBorder(), ), ); } }实战案例案例1登录表单class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); override Widget build(BuildContext context) { final emailController TextEditingController(); final passwordController TextEditingController(); return Scaffold( appBar: AppBar(title: const Text(登录)), body: Padding( padding: const EdgeInsets.all(16), child: Form( child: Column( children: [ TextFormField( controller: emailController, decoration: const InputDecoration( labelText: 邮箱, prefixIcon: Icon(Icons.email), border: OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value null || value.isEmpty) { return 请输入邮箱; } final emailRegex RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$); if (!emailRegex.hasMatch(value)) { return 请输入有效的邮箱; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: passwordController, decoration: const InputDecoration( labelText: 密码, prefixIcon: Icon(Icons.lock), border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) { return 请输入密码; } if (value.length 6) { return 密码至少6个字符; } return null; }, ), const SizedBox(height: 24), ElevatedButton( onPressed: () { // 处理登录逻辑 print(登录: ${emailController.text}); }, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text(登录), ), ], ), ), ), ); } }案例2注册表单class RegisterScreen extends StatefulWidget { const RegisterScreen({super.key}); override StateRegisterScreen createState() _RegisterScreenState(); } class _RegisterScreenState extends StateRegisterScreen { final _formKey GlobalKeyFormState(); final _emailController TextEditingController(); final _passwordController TextEditingController(); final _confirmController TextEditingController(); bool _agreed false; override void dispose() { _emailController.dispose(); _passwordController.dispose(); _confirmController.dispose(); super.dispose(); } void _submit() { if (_formKey.currentState!.validate() _agreed) { // 处理注册逻辑 print(注册成功); } else if (!_agreed) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(请同意服务条款)), ); } } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(注册)), body: Padding( padding: const EdgeInsets.all(16), child: Form( key: _formKey, child: ListView( children: [ TextFormField( controller: _emailController, decoration: const InputDecoration( labelText: 邮箱, border: OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value null || value.isEmpty) return 请输入邮箱; if (!RegExp(r^[\w-\.]([\w-]\.)[\w-]{2,4}$).hasMatch(value)) { return 请输入有效的邮箱; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _passwordController, decoration: const InputDecoration( labelText: 密码, border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) return 请输入密码; if (value.length 8) return 密码至少8个字符; return null; }, ), const SizedBox(height: 12), TextFormField( controller: _confirmController, decoration: const InputDecoration( labelText: 确认密码, border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value null || value.isEmpty) return 请再次输入密码; if (value ! _passwordController.text) return 两次密码不一致; return null; }, ), const SizedBox(height: 16), Row( children: [ Checkbox( value: _agreed, onChanged: (value) { setState(() { _agreed value ?? false; }); }, ), const Text(我已阅读并同意服务条款), ], ), const SizedBox(height: 24), ElevatedButton( onPressed: _submit, style: ElevatedButton.styleFrom( minimumSize: const Size.fromHeight(50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text(注册), ), ], ), ), ), ); } }表单验证最佳实践1. 实时验证TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, // ... )2. 错误信息清晰// 好的错误信息 validator: (value) { if (value null || value.isEmpty) { return 请输入用户名; } if (value.length 3) { return 用户名至少需要3个字符; } return null; } // 避免模糊的错误信息 validator: (value) { if (value null || value.isEmpty || value.length 3) { return 输入无效; // 不好用户不知道具体哪里错了 } return null; }3. 输入限制TextField( maxLength: 50, inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r[a-zA-Z0-9])), ], )4. 键盘类型适配// 邮箱 TextField(keyboardType: TextInputType.emailAddress) // 手机号 TextField(keyboardType: TextInputType.phone) // 数字 TextField(keyboardType: TextInputType.number) // 多行文本 TextField( keyboardType: TextInputType.multiline, maxLines: null, )5. 表单焦点管理final _emailFocus FocusNode(); final _passwordFocus FocusNode(); TextField( focusNode: _emailFocus, textInputAction: TextInputAction.next, onSubmitted: (_) { FocusScope.of(context).requestFocus(_passwordFocus); }, ) TextField( focusNode: _passwordFocus, textInputAction: TextInputAction.done, onSubmitted: (_) { _passwordFocus.unfocus(); // 提交表单 }, )总结Flutter提供了强大的表单处理能力通过本文的学习你应该掌握了基础组件TextField、TextFormField、Form表单验证内置验证、正则表达式验证、自定义验证器状态管理StatefulWidget、TextEditingController高级功能表单联动、动态字段、异步验证样式定制自定义输入框样式、图标、密码可见性切换核心要点使用Form组件管理表单状态使用TextFormField进行表单验证使用TextEditingController控制输入内容使用validator函数进行验证使用GlobalKeyFormState管理表单掌握这些技能后你可以创建出功能完善、用户体验良好的表单界面。