You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:50:17