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

Flutter未填文本框时SnackBar不显示的问题求助

问题解决:表单验证不触发提示SnackBar的问题

测试时故意留空部分文本框,未出现任何错误提示,尤其是SnackBar完全不显示,调整代码后仍无法解决,相关代码片段如下:

class _SignUpPageState extends State<SignUpPage> {

  // Focus nodes for email, password, and retyping passwords
  final FocusNode emailFocus = FocusNode();
  final FocusNode passwordFocus = FocusNode();
  final FocusNode retypePasswordFocus = FocusNode();

  // Bool values for obscuring text
  bool _obscureTextPassword = true;
  bool _obscureTextConfirmPassword = true;

  // Manages the state of the form
  final _formKey = GlobalKey<FormState>();

  // Refers to the name of the TextEditingController class
  TextEditingController _emailController = TextEditingController();
  TextEditingController _passwordController = TextEditingController();
  TextEditingController _retypePasswordController = TextEditingController();

  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    emailFocus.dispose();
    passwordFocus.dispose();
    retypePasswordFocus.dispose();
    super.dispose();
  }

  // Initializing these TextEditingController objects
  @override
  void initState() {
    super.initState();
    _emailController = TextEditingController();
    _passwordController = TextEditingController();
    _retypePasswordController = TextEditingController();
  }

  void _toggleSignUp() {
    setState(() {
      _obscureTextPassword = !_obscureTextPassword;
    });
  }

  void _toggleSignUpConfirm() {
    setState(() {
      _obscureTextConfirmPassword = !_obscureTextConfirmPassword;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Form(
        key: _formKey,
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Color.fromRGBO(73, 77, 235, 1.0),
                Color.fromRGBO(75, 0, 130, 0.8)
              ]
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: ListView(
              children: [
                SizedBox(height: 60,),
                Center(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text("Sign Up",
                      style: TextStyle(fontSize: 20, decoration: TextDecoration.none, color: Colors.white),),
                  ),
                ),
                SizedBox(height: 40,),
                Column(
                  children: [
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.emailAddress,
                        focusNode: emailFocus,
                        autofocus: true,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                          hintText: "Enter Your Email Address",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _emailController,
                        validator: (String? value) {
                          if (value == null || value.isEmpty) {
                            return "Please enter some text";
                          }
                          return null;
                        },
                      ),
                    ),
                    SizedBox(height: 40,),
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.visiblePassword,
                        focusNode: passwordFocus,
                        obscureText: _obscureTextPassword,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                          hintText: "Password",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _passwordController,
                      ),
                    ),
                    SizedBox(height: 40,),
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.visiblePassword,
                        obscureText: _obscureTextConfirmPassword,
                        textInputAction: TextInputAction.done,
                        decoration: InputDecoration(
                          hintText: "Retype Password",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _retypePasswordController,
                      ),
                    ),
                  ],
                ),
                SizedBox(height: 60,),
                ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.black,
                    padding: const EdgeInsets.symmetric(horizontal: 110, vertical: 25),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20)
                    )
                  ),
                  child: const Text(
                    'Next',
                    style: TextStyle(fontSize: 12),
                  ),
                  onPressed: () {
                    if (_formKey.currentState!.validate()) {
                      final snackBar = SnackBar(
                        /// need to set following properties for best effect of awesome_snackbar_content
                        elevation: 5,
                        behavior: SnackBarBehavior.floating,
                        backgroundColor: Colors.transparent,
                        content: AwesomeSnackbarContent(
                          title: 'On Snap!',
                          message: 'This is an example error message that will be shown in the body of snackbar!',
                          /// change contentType to ContentType.success, ContentType.warning or ContentType.help for variants
                          contentType: ContentType.failure,
                        ),
                      );
                    } else {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => const TabNav()),
                      );
                    }
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

问题根源分析

  • 表单验证逻辑颠倒:validate()返回true表示验证通过,此时应该执行页面跳转;而验证不通过(返回false)时才需要触发错误提示SnackBar,原代码逻辑完全相反
  • SnackBar创建后未调用显示方法:仅创建SnackBar实例但未执行ScaffoldMessenger.of(context).showSnackBar(snackBar),导致SnackBar从未被渲染
  • 密码与确认密码输入框缺失校验逻辑:这两个TextFormField未配置validator,留空时不会触发表单验证,导致表单整体验证结果不符合预期

修复后的完整代码

class _SignUpPageState extends State<SignUpPage> {

  // Focus nodes for email, password, and retyping passwords
  final FocusNode emailFocus = FocusNode();
  final FocusNode passwordFocus = FocusNode();
  final FocusNode retypePasswordFocus = FocusNode();

  // Bool values for obscuring text
  bool _obscureTextPassword = true;
  bool _obscureTextConfirmPassword = true;

  // Manages the state of the form
  final _formKey = GlobalKey<FormState>();

  // TextEditingController instances
  late TextEditingController _emailController;
  late TextEditingController _passwordController;
  late TextEditingController _retypePasswordController;

  @override
  void dispose() {
    // Clean up all resources
    emailFocus.dispose();
    passwordFocus.dispose();
    retypePasswordFocus.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _retypePasswordController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    _emailController = TextEditingController();
    _passwordController = TextEditingController();
    _retypePasswordController = TextEditingController();
  }

  void _toggleSignUp() {
    setState(() {
      _obscureTextPassword = !_obscureTextPassword;
    });
  }

  void _toggleSignUpConfirm() {
    setState(() {
      _obscureTextConfirmPassword = !_obscureTextConfirmPassword;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Form(
        key: _formKey,
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Color.fromRGBO(73, 77, 235, 1.0),
                Color.fromRGBO(75, 0, 130, 0.8)
              ]
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: ListView(
              children: [
                SizedBox(height: 60,),
                Center(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text("Sign Up",
                      style: TextStyle(fontSize: 20, decoration: TextDecoration.none, color: Colors.white),),
                  ),
                ),
                SizedBox(height: 40,),
                Column(
                  children: [
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.emailAddress,
                        focusNode: emailFocus,
                        autofocus: true,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                          hintText: "Enter Your Email Address",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _emailController,
                        validator: (String? value) {
                          if (value == null || value.isEmpty) {
                            return "Please enter your email";
                          }
                          // 可添加邮箱格式校验
                          final emailRegExp = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
                          if (!emailRegExp.hasMatch(value)) {
                            return "Please enter a valid email";
                          }
                          return null;
                        },
                      ),
                    ),
                    SizedBox(height: 40,),
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.visiblePassword,
                        focusNode: passwordFocus,
                        obscureText: _obscureTextPassword,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                          hintText: "Password",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _passwordController,
                        validator: (String? value) {
                          if (value == null || value.isEmpty) {
                            return "Please enter your password";
                          }
                          if (value.length < 6) {
                            return "Password must be at least 6 characters";
                          }
                          return null;
                        },
                      ),
                    ),
                    SizedBox(height: 40,),
                    Container(
                      height: 45,
                      width: 350,
                      padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
                      child: TextFormField(
                        keyboardType: TextInputType.visiblePassword,
                        obscureText: _obscureTextConfirmPassword,
                        textInputAction: TextInputAction.done,
                        decoration: InputDecoration(
                          hintText: "Retype Password",
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          contentPadding: EdgeInsets.all(30),
                        ),
                        controller: _retypePasswordController,
                        validator: (String? value) {
                          if (value == null || value.isEmpty) {
                            return "Please retype your password";
                          }
                          if (value != _passwordController.text) {
                            return "Passwords do not match";
                          }
                          return null;
                        },
                      ),
                    ),
                  ],
                ),
                SizedBox(height: 60,),
                ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.black,
                    padding: const EdgeInsets.symmetric(horizontal: 110, vertical: 25),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20)
                    )
                  ),
                  child: const Text(
                    'Next',
                    style: TextStyle(fontSize: 12),
                  ),
                  onPressed: () {
                    if (_formKey.currentState!.validate()) {
                      // 验证通过,执行页面跳转
                      Navigator.push(
                        context,
                        MaterialPageRoute(builder: (context) => const TabNav()),
                      );
                    } else {
                      // 验证不通过,显示错误提示SnackBar
                      final snackBar = SnackBar(
                        elevation: 5,
                        behavior: SnackBarBehavior.floating,
                        backgroundColor: Colors.transparent,
                        content: AwesomeSnackbarContent(
                          title: 'Error!',
                          message: 'Please fill in all required fields correctly',
                          contentType: ContentType.failure,
                        ),
                      );
                      ScaffoldMessenger.of(context).showSnackBar(snackBar);
                    }
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Jazil Zaim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 00:05:32