Flutter注册页使用SingleChildScrollView连接Firebase时出现UI错误
Flutter注册页UI错误及Firebase连接排查
我是Flutter新手,第一次在社区提问。母语不是英语,跟着YouTube教程开发首个移动端应用并尝试连接Firebase。不确定Firebase是否成功连接,因为运行应用进入注册页时出现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
相关产品推荐
相关产品推荐

