Center widget vertically inside a SingleChildScrollView
FlutterDartScrollviewFlutter Problem Overview
I'm new to Flutter so I train myself by making a simple form. I realized while I was debugging on my iPhone the virtual keyboard triggered an error: "A RenderFlex overflowed by 29 pixels on the bottom"
. I fixed this issue by wrapping my Container inside a SingleChildScrollView
.
The problem now is my Column's content is no longer centered. I can't figure out why ...
Here's my code to help you to understand :
List<Widget> _buildBody() {
var listWidget = List<Widget>();
SingleChildScrollView singleChild = SingleChildScrollView(
padding: EdgeInsets.only(top: 1.0),
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.all(30.0),
padding: EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 50.0),
child: Image.asset(
'assets/github.png',
width: 100.0,
height: 100.0,
),
),
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: TextFormField(
controller: _usernameController,
autofocus: true,
decoration: InputDecoration(
hintText: 'Username',
suffixIcon: Icon(Icons.account_circle)))),
Container(
child: TextFormField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
hintText: 'Password', suffixIcon: Icon(Icons.vpn_key)),
),
),
Container(
margin: EdgeInsets.only(top: 10.0),
child: RaisedButton(
splashColor: Colors.greenAccent,
color: Colors.blue,
child: Text('Submit'),
onPressed: () {
_handleSubmit();
},
),
)
],
),
),
));
listWidget.add(singleChild);
if (_requesting) {
var modal = new Stack(
children: [
new Opacity(
opacity: 0.3,
child: const ModalBarrier(dismissible: false, color: Colors.grey),
),
new Center(
child: new CircularProgressIndicator(),
),
],
);
listWidget.add(modal);
}
return listWidget;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Github Login'),
),
body: Stack(
children: _buildBody(),
));
}
I added the property "mainAxisAlignment: MainAxisAlignment.center" to my Column. It worked well before I wrapped it into the SingleChildScrollView.
If someone could help me and explain me why it doesn't work anymore I would really appreciated it :)
Flutter Solutions
Solution 1 - Flutter
ArtiomLK Suggested a solution in comments which helped me:
wrap SingleChildScrollView
in a Center
. The widgets tree is:
Center( child: SingleChildScrollView( child: Column(...)))
None of the others helped.
Solution 2 - Flutter
Solution:
Put your top level Stack
inside Center
widget.
body: Center(child: Stack(
children: _buildBody(),
)));
Tip to debug:
Use Flutter Inspector
to find where the layout is going wrong.
I edited your code a bit(to make to work in my local) and then I inspected. It showed like below
We have a Stack
and SingleChildScrollView
as per code(refer to the right side of the diagram where the stack of widgets are displayed). As size is determined by SingleChildScrollView
(contents inside it), Stack
occupies only a little space and by default, it aligned at top
. So put it under Center
, the whole Stack view will come in the center.
Solution 3 - Flutter
You can use "Center" widget like as
return Center( child: SingleChildScrollView() )
Solution 4 - Flutter
There's a section about it in the official docs:
> Using SingleChildScrollView with a Column
Source: https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html
However I found that using a combination of the above worked better. Namely confining the Column
to the minimum size possible (MainAxisSize.min
). This should be fine, as the SingleChildScrollView
will take up as much space as is possible on screen, before scrolling can happen.
Widget _buildPortraitPage() {
return Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min, // <-- notice 'min' here. Important
children: [
Flexible(
child: Image.asset('assets/images/my-image.png'),
),
Flexible(
child: Text('My content'),
),
],
),
),
);
}
The layout engine in Flutter is pretty hard to figure out.
Solution 5 - Flutter
use LayoutBuilder widget to wrap all the widget and use Spacer widget before and after your centered widget inside the Column
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AppBar'),
),
body: LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth, minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Spacer(),
Container(
child: //your widget
),
Spacer()
]
),
)
)
);
})
);
}
}
Solution 6 - Flutter
Just wrap the Column
in a Center
. I used that for my apps and it seems to center the contents of my Column
even inside a SingleChildScrollView
.
Solution 7 - Flutter
There's another way to achieve this:
Center(
child: ListView(
shrinkWrap: true,
children: []
)
)
Solution 8 - Flutter
wrap SingleChildScrollView with center
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
Solution 9 - Flutter
You can use SingleChildScrollView -> ConstrainedBox(with min height and width) -> Center