Flutter中如何判断TextFormField是否为空并实现登录校验
Flutter伪登录实现:整合Validator完成输入校验
需求很明确:做一个无需Firebase的伪登录页面,校验邮箱和密码输入框是否为空——空的话登录按钮不干活,填完了就跳转到下一页。但现有代码里的Validator没起作用,问题出在这几个地方:
原代码的核心问题
- 用了
StatelessWidget,但输入校验需要维护状态,得改成StatefulWidget TextFormField的validator必须配合Form组件才能触发,单独用不会生效- 全局变量
emailIsFilled和passwordIsFilled的赋值用了==(比较)而不是=(赋值),逻辑完全错误 - 登录按钮的判断逻辑没触发表单校验,直接用全局变量判断不可靠
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:lectureswatcher/widgets/registration.dart'; import 'package:lectureswatcher/widgets/tabs.dart'; class Home extends StatefulWidget { const Home({super.key}); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { // 用于管理表单状态的全局key final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Scaffold( body: Container( padding: const EdgeInsets.symmetric(vertical: 30), width: double.infinity, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, colors: [ Colors.blue.shade900, Colors.teal.shade700, Colors.green.shade300, ], ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ const SizedBox(height: 80), Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const <Widget>[ Text('Login', style: TextStyle(color: Colors.white, fontSize: 50)), SizedBox(height: 10), Text('Welcome Back', style: TextStyle(color: Colors.white, fontSize: 19)) ], ), ), const SizedBox(height: 20), Expanded( child: Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(40), topRight: Radius.circular(40), bottomLeft: Radius.circular(50), bottomRight: Radius.circular(50), ), ), child: Padding( padding: const EdgeInsets.all(30), child: Form( key: _formKey, child: Column( children: <Widget>[ const SizedBox(height: 60), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: const [ BoxShadow( blurRadius: 20, color: Color.fromARGB(73, 1, 58, 116), offset: Offset(0, 10), ) ], ), child: Column( children: <Widget>[ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade200)), ), child: TextFormField( decoration: const InputDecoration( hintText: "E-mail", hintStyle: TextStyle(color: Colors.grey), border: InputBorder.none, ), validator: (value) { if (value == null || value.isEmpty) { return '请输入邮箱'; } return null; }, ), ), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade200)), ), child: TextFormField( obscureText: true, // 密码框隐藏输入内容 decoration: const InputDecoration( hintText: "Password", hintStyle: TextStyle(color: Colors.grey), border: InputBorder.none, ), validator: (value) { if (value == null || value.isEmpty) { return '请输入密码'; } return null; }, ), ), ], ), ), const SizedBox(height: 60), TextButton( child: const Text("Registrate", style: TextStyle(color: Colors.grey)), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const Registration()), ); }, ), const SizedBox(height: 60), Container( height: 50, width: 300, margin: const EdgeInsets.symmetric(horizontal: 50), decoration: BoxDecoration( borderRadius: BorderRadius.circular(50), color: const Color.fromARGB(73, 1, 58, 116), ), child: TextButton( onPressed: () { // 触发所有输入框的校验逻辑 if (_formKey.currentState!.validate()) { // 校验通过后跳转页面 Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => const Tabs()), (Route<dynamic> route) => false, ); } }, child: const Text( "Login", style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold), ), ), ), const SizedBox(height: 90), ], ), ), ), ), ), ], ), ), ); } }
关键改动说明
- 切换为
StatefulWidget:表单状态需要动态维护,StatelessWidget无法满足需求 - 引入
Form组件:将两个输入框包裹其中,通过GlobalKey<FormState>统一控制表单校验 - 简化
validator逻辑:去掉无效的全局变量,校验不通过返回提示文本,通过则返回null - 重构登录按钮逻辑:调用
validate()触发全表单校验,仅当所有输入合法时才执行页面跳转 - 增加密码框隐藏:给密码输入框添加
obscureText: true,符合密码输入的常规体验
内容的提问来源于stack exchange,提问作者Jamila
相关产品推荐
相关产品推荐

