75

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 :)

Hurobaki
  • 3,728
  • 6
  • 24
  • 41
  • It doesn't make sense to vertically center a vertically scrollable content. Your scroll should be within the centered content, not on its parent – Rémi Rousselet Nov 20 '18 at 17:42
  • So I have to put my SingleChildScrollView inside Column’s children ? But where should I put all my containers ? @RémiRousselet – Hurobaki Nov 20 '18 at 17:51

11 Answers11

161

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.

AndrewS
  • 2,679
  • 2
  • 14
  • 23
  • 11
    this was the fix for me as well! – Ned Jan 12 '20 at 16:05
  • 2
    Yes this helped! In case it throws an "Incorrect use of ParentDataWidget" exception and your widget tree looks like this: Center > Expanded > SingleChildScrollView. Just delete the Expanded widget and you are good to go! – Carlit0 Jan 23 '21 at 18:40
  • @Carlit0 you can also wrap SingleChildScrollView. with SizedBox instade of Deleting -------------------------------------> Center > Expanded > SizedBox>SingleChildScrollView<---------- – Sonu kumar Feb 24 '22 at 00:09
  • earlier for me it was a good fix but it forces the list to center and space is left on the top if there is not enough list items . – appdev Jul 20 '22 at 07:53
44

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

enter image description here

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.

Dinesh Balasubramanian
  • 20,532
  • 7
  • 64
  • 57
  • Thank you it works like a charm ! I was focus on the Column's behaviour I didn't think about Center the whole Stack ... – Hurobaki Nov 21 '18 at 09:53
21

You can use "Center" widget like as

return Center( child: SingleChildScrollView() )

Musfiq Shanta
  • 1,298
  • 13
  • 9
18

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()
                        ]
                    ),
                  )
              )
          );
        })
    );
  }
}
Amera Abdallah
  • 638
  • 7
  • 5
  • This is great. I had to remove the IntrinsicHeight to prevent an overflow, but it still worked fine. When the keyboard appears things scroll nicely. – Gazihan Alankus Jun 21 '21 at 05:10
16

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.

DarkNeuron
  • 7,981
  • 2
  • 43
  • 48
6

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.

Coder
  • 345
  • 1
  • 4
  • 14
  • Thank you for your answer but unfortunately it doesn't work for my case :/ – Hurobaki Nov 21 '18 at 10:02
  • 21
    It did work on my case, but I wrapped the `SingleChildScrollView` in a `Center`. The widgets tree is: ```Center( child: SingleChildScrollView( child: Column(...``` – ArtiomLK May 12 '19 at 00:36
  • I was searching a fix for this for a long time, this is the only way it worked for me. Thanks @ArtiomLK ! – Iosif Pop Feb 11 '21 at 18:19
6

wrap SingleChildScrollView with center

child: Center(
   child: SingleChildScrollView(
      child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         mainAxisSize: MainAxisSize.max,

center in SingleChildScrollView

Sonu kumar
  • 351
  • 3
  • 7
5

There's another way to achieve this:

Center(
    child: ListView(
        shrinkWrap: true,
        children: []
    )

)
Matt
  • 665
  • 6
  • 16
3

use SingleChildScrollView widget

body: Center(
    child: SingleChildScrollView(
      scrollDirection: Axis.vertical,
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
2

Wrap your SingleChildScrollView(), with center. and here you go.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 10 '22 at 21:51
0

You can use SingleChildScrollView -> ConstrainedBox(with min height and width) -> Center