Flutter键盘弹出时布局溢出无法滚动,加SingleChildScrollView报错如何解决?
问题修复方案
核心问题原因
你之前添加SingleChildScrollView报错的核心原因是:SingleChildScrollView属于无边界高度的滚动容器,而你的SignUp/SignIn页面内部使用了Expanded组件,Expanded需要在有确定高度的父容器中才能正常计算尺寸,二者冲突导致渲染错误;同时你手动设置了resizeToAvoidBottomInset: false,关闭了Flutter自动适配键盘弹出的布局调整逻辑,进一步加剧了溢出问题。
具体修改步骤
1. 调整Scaffold基础配置
找到_DateTrackerState的build方法中的Scaffold配置,删除resizeToAvoidBottomInset: false这一行(默认值为true,会自动调整布局避让键盘),同时给返回的登录注册页面套上SingleChildScrollView,修改后代码:
@override Widget build(BuildContext context) { return Scaffold( backgroundColor: blue, body: SafeArea( child: FutureBuilder( future: _initializeFlutterFireFuture, builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.done: if (snapshot.hasError) { return Center( child: Text('错误: ${snapshot.error}', style: TextStyle(color: Colors.white),), ); } // 套上SingleChildScrollView支持滚动 return SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), child: signUp? SignUp(changeWidget) : SignIn(changeWidget), ); default: return const Center(child: Text('加载中...', style: TextStyle(color: Colors.white))); } }, ), ), ); }
2. 调整SignUp、SignIn页面布局
删除两个页面内部所有的Expanded组件,把外层Column的mainAxisAlignment从spaceEvenly改成MainAxisSize.min配合固定间距适配滚动逻辑,以SignUp页面为例,修改后build方法代码:
@override Widget build(BuildContext context) { return Center( child: Padding( padding: const EdgeInsets.symmetric(vertical: 24.0), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Container(width: widthCalculator(context),child: Image.asset('images/icon_launcher.png')), SizedBox(height: 32,), Form( key: _formKey, child: Container( margin: EdgeInsets.symmetric(horizontal: 16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text('Date Tracker', style: TextStyle(fontSize: 20.0, color: Colors.white),), Text('创建你的账号', style: TextStyle(fontSize: 16.0, color: Colors.white),), SizedBox(height: 16.0,), TextFormField( validator: (value)=> RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(_controllerEmail.text) ? null : '请输入有效的邮箱地址', keyboardType: TextInputType.emailAddress, controller: _controllerEmail, showCursor: true, decoration: InputDecoration( labelText: '邮箱', floatingLabelBehavior: FloatingLabelBehavior.never, border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(0))), fillColor: Colors.grey[100], filled: true, ), ), SizedBox(height: 16.0,), TextFormField( validator: (value)=> _controllerPass.text.length>=6 ? null : '密码最少6位', keyboardType: TextInputType.visiblePassword, obscureText: true, showCursor: true, controller: _controllerPass, decoration: InputDecoration( labelText: '密码', floatingLabelBehavior: FloatingLabelBehavior.never, border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(0))), fillColor: Colors.grey[300], filled: true, ), ), SizedBox(height: 16.0,), TextFormField( validator: (value)=> _controllerPass.text.length>=6 && _controllerPass.text != _controllerRepeatPass.text? '两次输入的密码不一致' : null, keyboardType: TextInputType.visiblePassword, obscureText: true, showCursor: true, controller: _controllerRepeatPass, decoration: InputDecoration( labelText: '重复密码', floatingLabelBehavior: FloatingLabelBehavior.never, border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(0))), fillColor: Colors.grey[300], filled: true, ), ), ], ), ), ), SizedBox(height: 32,), InkWell( onTap: () async { if (_formKey.currentState!.validate()) { if (kDebugMode) print('点击提交 - 注册用户'); busyChanger(true); UserCredential? userCredential = await registerUser(_controllerEmail.text, _controllerPass.text, context); busyChanger(false); if (userCredential!=null){ if (kDebugMode) print ('登录身份: '+userCredential.user!.email!) ; Navigator.pushReplacementNamed(context, '/afterLogin'); } } }, child: busy? Center(child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation<Color>(Colors.white),)): Container( padding: EdgeInsets.symmetric(vertical: 18.0), decoration: BoxDecoration( color: lGreen, borderRadius: BorderRadius.all(Radius.circular(10.0)) ), width: widthCalculator(context), child: Center(child: Text('提交', style: TextStyle(fontSize: 16.0),))), ), SizedBox(height: 24,), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('已有账号?', style: TextStyle(color: Colors.white),), GestureDetector( onTap: widget.callBack, child: Text(' 去登录 ', style: TextStyle(color: lGreen)), ) ], ) ], ), ), ); }
SignIn页面按照同样逻辑修改即可:删除内部Expanded,用固定SizedBox控制间距,同时把密码输入框的类型改为可见密码、添加隐藏密码属性,把提示文字翻译成中文即可。
内容的提问来源于stack exchange,提问作者Damandroid
相关产品推荐
相关产品推荐

