Flutter注册UI优化需求:布局调整与验证码输入框添加
注册UI实现问题与修复方案
效果对比
当前实现代码
@override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Column( children: [ SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: Stack(children: <Widget>[ Positioned( child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.4, color: const Color(0xff32394a), child: Center( child: MaterialButton( onPressed: () {}, child: const Text( 'AppName', style: TextStyle( fontSize: 40, fontWeight: FontWeight.bold, color: Colors.white ), ))), )), Positioned( top: MediaQuery.of(context).size.height * 0.4 - 100, left: 32, right: 32, child: Column( children: [ Container( width: MediaQuery.of(context).size.width - 64, decoration: BoxDecoration( color: const Color(0xffFFFFFF), borderRadius: BorderRadius.circular(20), border: Border.all( color: const Color(0xffe8e8e8), // Set the border color here width: 2.0, // Set the border width ), ), padding: const EdgeInsets.all(32), child: Column( children: [ Container( margin: const EdgeInsets.only(bottom: 32), child: const Text( 'Sign Up', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), ), ), Container( margin: const EdgeInsets.only(bottom: 16), child: TextField( cursorColor: const Color(0x9932394a), decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Full Name', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Container( margin: const EdgeInsets.only(bottom: 16), child: TextField( cursorColor: const Color(0x9932394a), decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Email', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Container( margin: const EdgeInsets.only(bottom: 16), child: TextField( cursorColor: const Color(0x9932394a), keyboardType: TextInputType.phone, maxLength: 10, maxLengthEnforcement: MaxLengthEnforcement.enforced, decoration: InputDecoration( prefixIcon: Icon(Icons.arrow_drop_down), labelText: '+1', suffixIconColor: const Color(0x9932394a), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Phone Number', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Container( margin: const EdgeInsets.only(bottom: 16), child: TextField( cursorColor: const Color(0x9932394a), decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Username', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Container( margin: const EdgeInsets.only(bottom: 20), child: TextField( cursorColor: const Color(0x9932394a), controller: password_textfield, obscureText: !_passwordVisible, decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Password', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), suffixIcon: IconButton( icon: Icon( // Based on passwordVisible state choose the icon _passwordVisible ? Icons.visibility : Icons.visibility_off, color: const Color(0x9932394a), ), onPressed: () { // Update the state i.e. toogle the state of passwordVisible variable setState(() { _passwordVisible = !_passwordVisible; }); }, ), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Container( margin: const EdgeInsets.only(bottom: 20), child: TextField( cursorColor: const Color(0x9932394a), controller: confirm_password_textfield, obscureText: !_confirmpasswordVisible, decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), hintText: 'Confirm Password', hintStyle: TextStyle(color: const Color(0x99d1d1d1)), suffixIcon: IconButton( icon: Icon( // Based on passwordVisible state choose the icon _confirmpasswordVisible ? Icons.visibility : Icons.visibility_off, color: const Color(0x9932394a), ), onPressed: () { // Update the state i.e. toogle the state of passwordVisible variable setState(() { _confirmpasswordVisible = !_confirmpasswordVisible; }); }, ), contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), Row( mainAxisSize: MainAxisSize.max, children: [ Expanded( child: ElevatedButton( onPressed: () { StartRegistration(); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0x9932394a), minimumSize: Size(double.infinity, 50), textStyle: TextStyle( fontWeight: FontWeight.bold, fontSize: 18 ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), // Adjust the value as per your requirement ), ), child: const Text("Register", style: TextStyle( color: Colors.white, )), ), ), ], ), const SizedBox( height: 25, ), ], ), ), Container( margin: const EdgeInsets.only(top: 32), child: TextButton( onPressed: () async{ Navigator.of(context).pop(); }, child: RichText( text: TextSpan( children: <TextSpan>[ TextSpan( text: "Back to", style: TextStyle(color: Colors.black, fontSize: 15.0), ), TextSpan( text: ' Sign In', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 15.0), ), ], ), ), ), ) ], )), ]), ), ], ), ), ); }
待解决问题
- 顶部深色区域中的"AppName"文本需要移至顶部位置,同时上移注册卡片,确保“返回登录”文本完整可见;
- 添加手机号验证码输入框(参考目标UI样式),并让TextField的提示文本在初始状态下可见,而非仅在获取焦点时显示。
修复方案
问题1修复:调整布局位置
- 移动AppName到顶部:将深色容器内的
Center替换为Align,设置alignment: Alignment.topCenter,并添加顶部内边距让文本靠顶部显示;同时缩小深色区域高度,给下方卡片留出更多空间。 - 上移注册卡片:修改
Positioned的top值,让卡片整体上移,确保底部的“返回登录”文本不被屏幕遮挡。
修改后的深色容器代码:
Positioned( child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.35, color: const Color(0xff32394a), padding: const EdgeInsets.only(top: 40), child: Align( alignment: Alignment.topCenter, child: MaterialButton( onPressed: () {}, child: const Text( 'AppName', style: TextStyle( fontSize: 40, fontWeight: FontWeight.bold, color: Colors.white ), ))), )),
注册卡片的Positioned修改:
Positioned( top: MediaQuery.of(context).size.height * 0.35 - 100, left: 32, right: 32, child: Column(...)
问题2修复:添加验证码输入框并调整提示文本
- 添加验证码输入框:在手机号输入框后新增一个
Row,包含验证码输入框和“发送验证码”按钮,匹配目标UI样式。 - 让提示文本始终可见:将所有
TextField的hintText替换为labelText,并设置floatingLabelBehavior: FloatingLabelBehavior.never,确保标签文本始终显示在输入框内。
示例验证码输入框代码:
Container( margin: const EdgeInsets.only(bottom: 16), child: Row( children: [ Expanded( child: TextField( cursorColor: const Color(0x9932394a), keyboardType: TextInputType.number, decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), labelText: 'Verification Code', labelStyle: TextStyle(color: const Color(0x99d1d1d1)), floatingLabelBehavior: FloatingLabelBehavior.never, contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), ), ), const SizedBox(width: 12), TextButton( onPressed: () { // 发送验证码逻辑 }, child: const Text( 'Send Code', style: TextStyle(color: Color(0x9932394a)), ), ) ], ), )
其他TextField的修改示例(以Full Name为例):
TextField( cursorColor: const Color(0x9932394a), decoration: InputDecoration( focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: const Color(0x9932394a)), borderRadius: BorderRadius.circular(16), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16)), labelText: 'Full Name', labelStyle: TextStyle(color: const Color(0x99d1d1d1)), floatingLabelBehavior: FloatingLabelBehavior.never, contentPadding: const EdgeInsets.only( left: 16, right: 16, top: 8, bottom: 8)), )
内容的提问来源于stack exchange,提问作者Sreejith Sree
相关产品推荐
相关产品推荐

