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

Flutter注册页使用SingleChildScrollView连接Firebase时出现UI错误

Flutter注册页UI错误及Firebase连接排查

我是Flutter新手,第一次在社区提问。母语不是英语,跟着YouTube教程开发首个移动端应用并尝试连接Firebase。不确定Firebase是否成功连接,因为运行应用进入注册页时出现UI错误。

错误截图

注册页UI错误

代码

import 'package:dfu_check_application/common/auth_controller.dart';
import 'package:flutter/material.dart';
import 'package:dfu_check_application/common/theme_helper.dart';
import 'package:dfu_check_application/pages/widgets/header_widget.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:firebase_auth/firebase_auth.dart';

import 'profile_page.dart';

class RegistrationPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _RegistrationPageState();
  }
}

class _RegistrationPageState extends State<RegistrationPage> {
  final _formKey = GlobalKey<FormState>();
  bool checkedValue = false;
  bool checkboxValue = false;

  @override
  Widget build(BuildContext context) {
    var nameController = TextEditingController();
    var emailController = TextEditingController();
    var passwordController = TextEditingController();
    return Scaffold(
      backgroundColor: Colors.white,
      body: SingleChildScrollView(
        child: Stack(children: [
          Container(
            height: 150,
            child: HeaderWidget(150, false, Icons.person_add_alt_1_rounded),
          ),
          Container(
            margin: EdgeInsets.fromLTRB(25, 50, 25, 10),
            padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
            alignment: Alignment.center,
            child: Column(
              children: [
                Form(
                  key: _formKey,
                  child: Column(
                    children: [
                      GestureDetector(
                        child: Stack(
                          children: [
                            Container(
                              padding: EdgeInsets.all(10),
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(100),
                                border:
                                    Border.all(width: 5, color: Colors.white),
                                color: Colors.white,
                                boxShadow: [
                                  BoxShadow(
                                    color: Colors.black12,
                                    blurRadius: 20,
                                    offset: const Offset(5, 5),
                                  ),
                                ],
                              ),
                              child: Icon(
                                Icons.person,
                                color: Colors.grey.shade300,
                                size: 80.0,
                              ),
                            ),
                            Container(
                              padding: EdgeInsets.fromLTRB(80, 80, 0, 0),
                              child: Icon(
                                Icons.add_circle,
                                color: Colors.grey.shade700,
                                size: 25.0,
                              ),
                            ),
                          ],
                        ),
                      ),
                      SizedBox(
                        height: 30,
                      ),
                      Container(
                        child: TextFormField(
                          controller: nameController,
                          decoration: ThemeHelper().textInputDecoration(
                              'Full Name', 'Enter your full name'),
                        ),
                        decoration: ThemeHelper().inputBoxDecorationShaddow(),
                      ),
                      SizedBox(
                        height: 30,
                      ),
                      SizedBox(height: 20.0),
                      Container(
                        child: TextFormField(
                          controller: emailController,
                          decoration: ThemeHelper().textInputDecoration(
                              "E-mail address", "Enter your email"),
                          keyboardType: TextInputType.emailAddress,
                          validator: (val) {
                            // ignore: prefer_is_not_empty
                            if (!(val!.isEmpty) &&
                                !RegExp(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$")
                                    .hasMatch(val)) {
                              return "Enter a valid email address";
                            }
                            return null;
                          },
                        ),
                        decoration: ThemeHelper().inputBoxDecorationShaddow(),
                      ),
                      SizedBox(height: 20.0),
                      Container(
                        child: TextFormField(
                          obscureText: true,
                          controller: passwordController,
                          decoration: ThemeHelper().textInputDecoration(
                              "Password*", "Enter your password"),
                          validator: (val) {
                            if (val!.isEmpty) {
                              return "Please enter your password";
                            }
                            return null;
                          },
                        ),
                        decoration: ThemeHelper().inputBoxDecorationShaddow(),
                      ),
                      SizedBox(height: 15.0),
                      FormField<bool>(
                        builder: (state) {
                          return Column(
                            children: <Widget>[
                              Row(
                                children: <Widget>[
                                  Checkbox(
                                      value: checkboxValue,
                                      onChanged: (value) {
                                        setState(() {
                                          checkboxValue = value!;
                                          state.didChange(value);
                                        });
                                      }),
                                  Text(
                                    "I accept all terms and conditions.",
                                    style: TextStyle(color: Colors.grey),
                                  ),
                                ],
                              ),
                              Container(
                                alignment: Alignment.centerLeft,
                                child: Text(
                                  state.errorText ?? '',
                                  textAlign: TextAlign.left,
                                  style: TextStyle(
                                    color: Theme.of(context).errorColor,
                                    fontSize: 12,
                                  ),
                                ),
                              )
                            ],
                          );
                        },
                        validator: (value) {
                          if (!checkboxValue) {
                            return 'You need to accept terms and conditions';
                          } else {
                            return null;
                          }
                        },
                      ),
                      SizedBox(height: 20.0),
                      GestureDetector(
                        onTap: () {
                          AuthController.instance.register(
                              nameController.text.trim(),
                              emailController.text.trim(),
                              passwordController.text.trim());
                        },
                      ),
                      Container(
                        decoration: ThemeHelper().buttonBoxDecoration(context),
                        child: ElevatedButton(
                          style: ThemeHelper().buttonStyle(),
                          child: Padding(
                            padding: const EdgeInsets.fromLTRB(40, 10, 40, 10),
                            child: Text(
                              "Register".toUpperCase(),
                              style: TextStyle(
                                fontSize: 20,
                                fontWeight: FontWeight.bold,
                                color: Colors.white,
                              ),
                            ),
                          ),
                          onPressed: () {
                            if (_formKey.currentState!.validate()) {
                              Navigator.of(context).pushAndRemoveUntil(
                                  MaterialPageRoute(
                                      builder: (context) => ProfilePage()),
                                  (Route<dynamic> route) => false);
                            }
                          },
                        ),
                      ),
                      SizedBox(height: 30.0),
                      Text(
                        "Or create account using social media",
                        style: TextStyle(color: Colors.grey),
                      ),
                      SizedBox(height: 25.0),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          GestureDetector(
                            child: FaIcon(
                              FontAwesomeIcons.google,
                              size: 35,
                              color: HexColor("#EC2D2F"),
                            ),
                            onTap: () {
                              setState(() {
                                showDialog(
                                  context: context,
                                  builder: (BuildContext context) {
                                    return ThemeHelper().alartDialog(
                                        "Google Account",
                                        "You tap on Google icon.",
                                        context);
                                  },
                                );
                              });
                            },
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ]),
      ),
    );
  }
}

问题修复及优化建议

  • 移除空的GestureDetector:代码中有一个没有子组件的GestureDetector,这会导致布局错误(大概率是你看到的UI问题),直接删除该组件即可。
  • 调整控制器声明位置:将nameController、emailController、passwordController移到State类的成员变量中,不要在build方法内声明,否则每次界面重建都会重置控制器,导致输入内容丢失:
    class _RegistrationPageState extends State<RegistrationPage> {
      final _formKey = GlobalKey<FormState>();
      bool checkedValue = false;
      bool checkboxValue = false;
      // 移到这里作为成员变量
      final nameController = TextEditingController();
      final emailController = TextEditingController();
      final passwordController = TextEditingController();
    
      @override
      void dispose() {
        // 记得销毁控制器,避免内存泄漏
        nameController.dispose();
        emailController.dispose();
        passwordController.dispose();
        super.dispose();
      }
    
      // ... 其余代码
    }
    
  • 修正注册按钮逻辑:当前注册按钮的onPressed只做了表单验证和页面跳转,没有调用Firebase注册方法。修改为:
    onPressed: () async {
      if (_formKey.currentState!.validate()) {
        try {
          // 调用注册方法
          await AuthController.instance.register(
            nameController.text.trim(),
            emailController.text.trim(),
            passwordController.text.trim(),
          );
          // 注册成功后再跳转
          Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(builder: (context) => ProfilePage()),
            (Route<dynamic> route) => false,
          );
        } catch (e) {
          // 捕获注册错误并提示用户
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text("注册失败: ${e.toString()}")),
          );
        }
      }
    },
    
  • 验证Firebase连接:可以在main.dart中添加Firebase初始化检查,确认连接状态:
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      print("Firebase初始化成功"); // 控制台打印确认
      runApp(MyApp());
    }
    
  • 优化Checkbox的FormField:FormField的validator可以直接使用传入的value参数,无需依赖外部的checkboxValue,让逻辑更清晰:
    validator: (value) {
      if (value != true) {
        return 'You need to accept terms and conditions';
      } else {
        return null;
      }
    },
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 01:48:20