Flutter:打开键盘时无法滚动表单 [英] Flutter: Unable to make the Form scroll when the Keyboard is open
问题描述
在我的应用程序中,我正在使用 stack
和 container
.在 container
中,我有一个 form
及其字段.下面是我的代码
import'package:flutter/cupertino.dart';导入'package:flutter/material.dart';导入'package:flutter/widgets.dart';类Login扩展StatelessWidget {@override窗口小部件build(BuildContext context){返回脚手架(backgroundColor:Colors.white,正文:LoginUI(),);}}LoginUI类扩展了StatefulWidget {@override状态< StatefulWidget>createState(){//TODO:实现createState返回LoginState();}}类LoginState扩展State< LoginUI>{final _formKey = GlobalKey< FormState>();@override窗口小部件build(BuildContext context){返回容器(高度:double.infinity,宽度:double.infinity,孩子:堆(适合:StackFit.loose,子代:< Widget> [安全区域(子代:集装箱(边距:EdgeInsets.only(top:25),子级:Image.asset("assets/images/login_image.png"),),),定位(最高:275,子代:集装箱(高度:600,宽度:MediaQuery.of(context).size.width,装饰:新BoxDecoration(颜色:Colors.white,borderRadius:新的BorderRadius.only(topLeft:const Radius.circular(40.0),topRight:const Radius.circular(40.0))),子:列(mainAxisAlignment:MainAxisAlignment.start,子代:< Widget> [排(mainAxisAlignment:MainAxisAlignment.center,子代:< Widget> [灵活的(子代:集装箱(利润:EdgeInsets.only(top:20,left:10,right:10),子:Image.asset("assets/images/logo_2.png"),),)],),形式(子:列(子代:< Widget> [容器(保证金:EdgeInsets.only(最高:40),子代:SizedBox(宽度:MediaQuery.of(context).size.width * .90,高度:36,子级:TextFormField(验证者:(值){如果(value.isEmpty){返回请输入一些文字";}返回null;},装饰:InputDecoration(填满:是的,fillColor:Colors.white,contentPadding:const EdgeInsets.only(顶部:2,底部:2,左侧:8),边框:OutlineInputBorder(borderRadius:BorderRadius.circular(30.0),),hintText:电话",),),)),容器(保证金:EdgeInsets.only(上:15),子代:SizedBox(高度:36,宽度:MediaQuery.of(context).size.width * .90,子级:TextFormField(验证者:(值){如果(value.isEmpty){返回请输入一些文字";}返回null;},装饰:InputDecoration(填满:是的,fillColor:Colors.white,contentPadding:const EdgeInsets.only(顶部:2,底部:2,左侧:8),边框:OutlineInputBorder(borderRadius:BorderRadius.circular(30.0),),hintText:密码",),),),),对齐(对齐方式:Alignment.bottomRight,子代:集装箱(保证金:EdgeInsets.only(上:1,左:10,右:10),子代:FlatButton(onPressed:(){},子代:文字(忘记密码?",样式:TextStyle(fontFamily:"Roboto-Medium",fontSize:14.0,letterSpacing:1.25,颜色:Color.fromRGBO(75,56,137,80))),)),),容器(利润:EdgeInsets.only(top:1,left:10,right:10),子代:SizedBox(宽度:MediaQuery.of(context).size.width * .90,子代:RaisedButton(颜色:Color.fromRGBO(75,56,137,80),textColor:Colors.white,形状:RoundedRectangleBorder(borderRadius:新的BorderRadius.circular(18.0),侧面:BorderSide(颜色:Color.fromRGBO(75,56,137,80))),子代:文字(登录",样式:Theme.of(context).textTheme.button,),onPressed:(){如果(_formKey.currentState.validate()){//如果表单有效,则显示一个Snackbar.Scaffold.of(context).showSnackBar(小吃店(内容:Text('处理数据')));}},),))],),),容器(边距:EdgeInsets.only(顶部:1,左:10,右:10),子代:FlatButton(onPressed:(){},子:RichText(文字:TextSpan(子级:< TextSpan> [TextSpan(文字:还不是会员?",样式:TextStyle(fontFamily:'Roboto-Regular',fontSize:14.0,letterSpacing:0.25,color:Color.fromRGBO(75,56,137,80)),),TextSpan(文字:创建帐户",样式:TextStyle(装饰:TextDecoration.underline,fontFamily:'Roboto-Regular',fontSize:14.0,letterSpacing:0.25,color:Color.fromRGBO(75,56,137,80),),)]),),)),],),),),],)//孩子:Image.asset("assets/images/login_image.png"),);}小部件_buildForm(){退货表格(密钥:_formKey,子:列(子代:< Widget> [排(mainAxisAlignment:MainAxisAlignment.center,子代:< Widget> [灵活的(弹性:1,子代:集装箱(子:ImageIcon(AssetImage("assets/images/email_24px.png"),颜色:Colors.white,),margin:EdgeInsets.only(right:5,bottom:30)),),灵活的(弹性:7子代:SizedBox(高度:80,子级:TextFormField(验证者:(值){如果(value.isEmpty){返回请输入一些文字";}返回null;},装饰:InputDecoration(填满:是的,fillColor:Colors.white,contentPadding:const EdgeInsets.only(top:2,bottom:2,left:8),边框:OutlineInputBorder(borderRadius:BorderRadius.circular(30.0),),hintText:电子邮件",),),))],),容器(边距:EdgeInsets.only(top:20),子级:Row(mainAxisAlignment:MainAxisAlignment.center,子代:< Widget> [灵活的(弹性:1,子代:集装箱(子:ImageIcon(AssetImage("assets/images/lock_24px.png"),颜色:Colors.white,),边距:EdgeInsets.only(右侧:5,底部:30),),),灵活的(弹性:7子代:SizedBox(高度:80,子级:TextFormField(验证者:(值){如果(value.isEmpty){返回请输入一些文字";}返回null;},装饰:InputDecoration(填满:是的,fillColor:Colors.white,contentPadding:const EdgeInsets.only(top:2,bottom:2,left:8),边框:OutlineInputBorder(borderRadius:BorderRadius.circular(30.0),),hintText:密码",),),))],),),容器(子级:Row(mainAxisAlignment:MainAxisAlignment.end,子代:< Widget> [FlatButton(materialTapTargetSize:MaterialTapTargetSize.shrinkWrap,子代:文字(忘记密码?",样式:Theme.of(context).textTheme.body1,),onPressed:(){},),],),),容器(边距:EdgeInsets.only(顶部:40,左侧:25,右侧:10,底部:20),子级:Row(mainAxisAlignment:MainAxisAlignment.center,子代:< Widget> [灵活的(子代:SizedBox(宽度:double.infinity,高度:45,子代:RaisedButton(颜色:Color.fromRGBO(0,72,128,100),textColor:Colors.white,形状:RoundedRectangleBorder(borderRadius:新的BorderRadius.circular(18.0),边:BorderSide(color:Color.fromRGBO(0,72,128,100))),子代:文字(登录",样式:Theme.of(context).textTheme.button,),onPressed:(){如果(_formKey.currentState.validate()){//如果表单有效,则显示一个Snackbar.Scaffold.of(context).showSnackBar(SnackBar(content:Text('Processing Data')));}},),))],),)],),);}@override无效的initState(){//TODO:实现initStatesuper.initState();}}
我的看法如下
打开键盘时,用户必须将其关闭才能访问 login
按钮.这是因为无法滚动.我尝试在主图像下方添加 SingleScrollView
和 ListView
,然后将其余的内容包装起来,但这没有用.它只会使内容消失.
如何确保 fORM
部分可滚动?
您可以使用 SingleChildScrollView
和 ConstrainedBox
包裹整个小部件,如下所示:
Scaffold(正文:SingleChildScrollView(子代:ConstrainedBox(约束:BoxConstraints(maxHeight:MediaQuery.of(context).size.height),子代:集装箱(子:yourWidget()
您可以在此处查看相关答案: https://stackoverflow.com/a/59783374/12709039 >
In my application, I am using a stack
and a container
. Within the container
i have a form
and its fields. Below is my code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class Login extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: LoginUI(),
);
}
}
class LoginUI extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginState();
}
}
class LoginState extends State<LoginUI> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Container(
height: double.infinity,
width: double.infinity,
child:
Stack(
fit: StackFit.loose,
children: <Widget>[
SafeArea(
child: Container(
margin: EdgeInsets.only(top: 25),
child: Image.asset("assets/images/login_image.png"),
),
),
Positioned(
top: 275,
child: Container(
height: 600,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(40.0),
topRight: const Radius.circular(40.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin:
EdgeInsets.only(top: 20, left: 10, right: 10),
child: Image.asset(
"assets/images/logo_2.png"),
),
)
],
),
Form(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(
top: 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width * .90,
height: 36,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Phone",
),
),
)),
Container(
margin: EdgeInsets.only(
top: 15,
),
child: SizedBox(
height: 36,
width: MediaQuery.of(context).size.width * .90,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Password",
),
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
margin: EdgeInsets.only(
top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {},
child: Text("Forgot Password?",
style: TextStyle(
fontFamily: 'Roboto-Medium',
fontSize: 14.0,
letterSpacing: 1.25,
color:
Color.fromRGBO(75, 56, 137, 80))),
)),
),
Container(
margin:
EdgeInsets.only(top: 1, left: 10, right: 10),
child: SizedBox(
width: MediaQuery.of(context).size.width * .90,
child: RaisedButton(
color: Color.fromRGBO(75, 56, 137, 80),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(18.0),
side: BorderSide(
color:
Color.fromRGBO(75, 56, 137, 80))),
child: Text(
"LOGIN",
style: Theme.of(context).textTheme.button,
),
onPressed: () {
if (_formKey.currentState.validate()) {
// If the form is valid, display a Snackbar.
Scaffold.of(context).showSnackBar(
SnackBar(
content:
Text('Processing Data')));
}
},
),
))
],
),
),
Container(
margin: EdgeInsets.only(top: 1, left: 10, right: 10),
child: FlatButton(
onPressed: () {},
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: "Not a member yet? ",
style: TextStyle(fontFamily: 'Roboto-Regular', fontSize: 14.0, letterSpacing: 0.25, color:Color.fromRGBO(75, 56, 137, 80 )),
),
TextSpan(
text: "Create an Account",
style: TextStyle(decoration: TextDecoration.underline, fontFamily: 'Roboto-Regular', fontSize: 14.0, letterSpacing: 0.25, color:Color.fromRGBO(75, 56, 137, 80 ),
),)
]),
),
)),
],
),
),
),
],
)
//child: Image.asset("assets/images/login_image.png"),
);
}
Widget _buildForm() {
return Form(
key: _formKey,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: ImageIcon(
AssetImage("assets/images/email_24px.png"),
color: Colors.white,
),
margin: EdgeInsets.only(right: 5, bottom: 30)),
),
Flexible(
flex: 7,
child: SizedBox(
height: 80,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Email",
),
),
))
],
),
Container(
margin: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: ImageIcon(
AssetImage("assets/images/lock_24px.png"),
color: Colors.white,
),
margin: EdgeInsets.only(right: 5, bottom: 30),
),
),
Flexible(
flex: 7,
child: SizedBox(
height: 80,
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.only(top: 2, bottom: 2, left: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Password",
),
),
))
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
child: Text(
"Forgot Password?",
style: Theme.of(context).textTheme.body1,
),
onPressed: () {},
),
],
),
),
Container(
margin: EdgeInsets.only(top: 40, left: 25, right: 10, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: SizedBox(
width: double.infinity,
height: 45,
child: RaisedButton(
color: Color.fromRGBO(0, 72, 128, 100),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side:
BorderSide(color: Color.fromRGBO(0, 72, 128, 100))),
child: Text(
"LOGIN",
style: Theme.of(context).textTheme.button,
),
onPressed: () {
if (_formKey.currentState.validate()) {
// If the form is valid, display a Snackbar.
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Processing Data')));
}
},
),
))
],
),
)
],
),
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
}
My view is as follows
when the keyboard is open, the user must close it to access the login
button. This is because this cannot be scrolled. I tried adding SingleScrollView
and ListView
below the main image and wrap the rest with it, but that didnt work. It only made the content disappear.
How can i make sure the fORM
section is scrollable?
You can wrap your whole widget with SingleChildScrollView
and then ConstrainedBox
as follows:
Scaffold(
body: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
child: Container(
child: yourWidget()
You can see the related answer here: https://stackoverflow.com/a/59783374/12709039
这篇关于Flutter:打开键盘时无法滚动表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!