I'm trying to create a scrollable register form for a Flutter app. I got SingleChildScroll to work, but theres a large padding or inset or something on top of the keyboard that can block content. You can see if pretty well If I scroll all they way to the bottom.
Here's my code.
Widget _buildContainer() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ClipRRect(
// This Clips the border Radius of the Container
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: Container(
// This sets the attributes of the Container
height: MediaQuery.of(context).size.height * 0.69,
width: MediaQuery.of(context).size.width * 0.9,
decoration: const BoxDecoration(
color: Colors.white,
),
child: Scaffold(
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFirstNameRow(),
_buildLastNameRow(),
_buildEmailRow(),
_buildPasswordRow(),
_buildConfirmPasswordRow(),
_buildRegisterButton(),
],
),
),
),
),
),
),
],
);
}
I've tried setting resizeToAvoidBottomInset: false, in the Scaffold, but that prevents any scrolling from happening.
I've also tried adding to Scaffold as well, but that only changes the padding around that mystery inset.
body: Padding(
padding: EdgeInsets.only(
bottom: 8.0),
Thanks for your Help!
Related
In my Flutter application I have a form which is encapsulated within a native view using hybrid composition. Tapping an input at the bottom of the form opens the keyboard. This causes the keyboard to overlap the focused form field.
How can I get the keyboard in Flutter to not overlap the form field in the native view component?
Below is my current layout:
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
margin: const EdgeInsets.fromLTRB(0, 20, 0, 0),
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Padding(
padding: EdgeInsets.all(30),
child: Container(
height: 520,
child: AddressDetailsNativeView(),
),
),
),
SizedBox(height: 20),
],
),
),
Take your column widget inside singlechildscroll view widget this will prevent the overlap of the keyboard.
SinglechildscrollView(
child:Column(
children:[
TextField(),
TextField()
]
I want the Container attached to the body of the Scaffold to occupy the space of it's child, which is the Padding widget in this case.
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
);
Below is the screenshot for the above code:
But I also want the padding widget to be pushed to the bottom of the screen. To achieve this I wrapped the Padding widget with the Expanded widget, and later wrapped the Expanded widget with a Column widget, as shown below:
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
// backgroundColor: AppColors.grey,
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () => Navigator.pushReplacementNamed(context, '/'),
),
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
],
),
),
);
Now that the contents of the Padding widget have got pushed to the bottom of the screen, but the Expanded widget, tries to occupy all the available space. I don't want this to happen.
I don't want the height of the Padding widget to increase. Below is the screenshot after updating the code:
Another issue that's concerning me is, where should I be adding the SingleChildScrollView, as I would experience the "Bottom overflowed by -- px" error when the user would tap on the TextFormFields to input the email and password.
I did raise this issue earlier as well but wasn't much luck, so thought would organize the code and explain it in detail so that it would be easy for others to understand and help.
Thank you so much for your help in advance.
AFTER APPLYING SOLUTION SUGGESTED BY #SoundConception
try adding this to your Column widget :
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
In your first code example you have:
...
body: Container(
...
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
The mainAxisSize: MainAxisSize.min specifies that the Column should be as small as possible in height, effectively shrink wrapping it to the height of its children.
The Padding just adds the specified dp of padding around Column widget.
This means the child of the Container has a fixed height equal to the sum of the Column children heights plus (kSpacingUnit * 3.0) dp of padding top and bottom.
Since the Container child height is fixed, the Container will size itself to the height of it's child.
In your second code example you have:
body: Container(
...
child: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
...
],
),
),
),
],
),
),
Here the outermost Column has a single child that is an Expanded which means this will take up all the available room in the Column.
The innermost Column has mainAxisAlignment: MainAxisAlignment.end meaning its children will align to the bottom of the Column. The height of your Padding has not expanded.
You ask about using a SingleChildScrollView. I assume you want the white background decoration to remain stationary, and only the contents of the Column should be able to scroll.
Try something like the following:
return Scaffold(
...
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
boxShadow: kBoxShadow,
),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(kSpacingUnit * 3.0),
child: Column(
children: <Widget>[
EmailSignInForm(),
SizedBox(height: kSpacingUnit * 4.0),
SocialMediaLoginWidget(),
],
),
),
),
),
);
Note: You'll need to make sure your EmailSignInForm() and SocialMediaLoginWidget() do not have unbound height.
My guess is your EmailSignInForm() probably utilises a Column. If so set it's mainAxisSize to min.
in this below code i have Wrap widget into TabBarView and i'm not sure as this widget size, when i use Container with specify height my problem solved, but i miss some layouts which i want to show that with map, how can i resolve this problem? i tested SizedBox.expand but it doesn't any change
Flexible(
child: TabBarView(
children: [
Center(
child: Wrap(
children: feeds.map((feed){
return Container(
width: MediaQuery.of(context).size.width /3.5,
height:MediaQuery.of(context).size.width /3.5,
margin: EdgeInsets.all(2.0),
child: GridTile(
header: feed.feedType ==1?Icon(Icons.video_call)
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(3.0)
child: Image.asset(feed.feedImage))),
),
);
}).toList(),
),
),
],
controller: tabController,
),
),
I'm building a layout with a GridView and Cards. I want to put a color to the bottom of each card. I found this question Fill an area with color in Flutter and tried to do the same trick for bottom, but each time The SizedBox Overflows the round card corners. Any idea of how to fix this?
The sample code below shows the issue. I try to color the bottom part of the card, and when I do this, the corners of the card are lost, like overflow from the Container.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
margin: EdgeInsets.all(20),
elevation: 10,
child: SizedBox(
height: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text("line1"),
Text(
"line2",
),
Expanded(
child: Container(
/*color: Colors.orange,*/ child: Text("Bottom"),
)),
],
),
),
),
Expanded(
child: Container(),
)
],
),
);
}
Try using BoxDecoration in your Container and use the same radius as your Card (4.0)
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4.0),
bottomRight: Radius.circular(4.0))),
child: Text("Bottom"),
),
),
I have the following code:
class _MyHomePageState extends State {
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return new Scaffold(
body: new Column(
children: [
new Container(
color: JBTheme.colorGreenBrand,
height: 130.0,
alignment: Alignment.bottomLeft,
child: new Center(
child: new Align(
alignment: Alignment.bottomCenter,
child: new Container(
color: JBTheme.colorOrange,
constraints: new BoxConstraints(maxWidth: 270.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Image.asset("flags/flag_dk.png"),
new Container(
margin: const EdgeInsets.only(top: 4.0, bottom: 4.0),
child: new Text("Danmark"),
),
new Text("DKK")
],
),
new Expanded(child: new Image.asset("images/arrow.png")),
new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Image.asset("flags/flag_us.png"),
new Container(
margin: const EdgeInsets.only(top: 4.0, bottom: 4.0),
child: new Text("USA"),
),
new Text("USD")
],
)
],
),
),
),
),
),
new Expanded(
child: new Container(
color: JBTheme.colorGreyMedium,
child: new Column(
children: [
new Expanded(child: new Container()),
new Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Card(
elevation: -8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: new Container(
width: 200.0,
height: 30.0,
color: JBTheme.colorWhite,
child: new Stack(
children: [
new TextField(
textAlign: TextAlign.center
)
],
)
),
)
)
],
),
)),
new Container(
height: 260.0,
color: JBTheme.colorGreenMint,
)
],
));
}
}
And it looks like this:
But when I click the TextField and the keyboard opens I get this:
I did not expect all of my layout to be moved up by the full keyboard height, I would like it to only move up enough so that the focused TextField is visible (and not to give a error). How can I fix this, and why is it happening?
Thank you
Søren
There are two solutions to this problem.
Add resizeToAvoidBottomPadding: false to your Scaffold
Scaffold(
resizeToAvoidBottomPadding: false,
body: ...)
Put your Scaffold body inside a scrollableView (like SingleChildScrollView or ListView)
new Scaffold(
body: SingleChildScrollView(child: //your existing body
...)
You can find similar problem and answer here
This is Flutters way of showing us how many pixels of content will be hidden from users eyesight when using the keypad. Try setting resizeToAvoidBottomPadding to false... From docs:
Whether the body (and other floating widgets) should size themselves
to avoid the window's bottom padding.
Scaffold(
resizeToAvoidBottomPadding: false,
This will avoid the resizing so you will at least avoid the dev warning being shown. But remember user will not see some content, and also this is a developer warning.
Update on 17/10/2019
resizeToAvoidBottomPadding is now Deprecated.
Use resizeToAvoidBottomInset to specify if the body should resize when the keyboard appears.
Scaffold(
resizeToAvoidBottomInset: false,
If you just use SingleChildScrollView content looses vertical alignment. You can also wrap the SingleChildScrollView in a Center Widget.
child: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>...
A full description of this error and two possible solutions can be found on Medium article available on https://medium.com/zipper-studios/the-keyboard-causes-the-bottom-overflowed-error-5da150a1c660. The last one works great for me.