Flutter - How to center widget inside list view
Asked Answered
S

12

89

I'm struggling with centering a widget inside listView.

I tried this, but Text('ABC') is not centered vertically. How can I achieve this?

new Scaffold(
  appBar: new AppBar(),
  body: new ListView(
    padding: const EdgeInsets.all(20.0),
    children: [
      new Center(
        child: new Text('ABC')
      )
    ]
  )
);
Stewardson answered 25/10, 2018 at 14:8 Comment(1)
Why are you using a ListView for that?Obtrude
U
168

Vertically Center & Horizontal Center:

Scaffold(
  appBar: new AppBar(),
  body: Center(
    child: new ListView(
      shrinkWrap: true,
        padding: const EdgeInsets.all(20.0),
        children: [
          Center(child: new Text('ABC'))
        ]
    ),
  ),
);

Only Vertical Center

Scaffold(
  appBar: new AppBar(),
  body: Center(
    child: new ListView(
      shrinkWrap: true,
        padding: const EdgeInsets.all(20.0),
        children: [
          new Text('ABC')
        ]
    ),
  ),
);
Urfa answered 25/10, 2018 at 14:19 Comment(5)
Thanks for sharing. This works. But I have a list of child, so I have to put on every child a center-widget :( Hope Flutter comes with a alignment-property on the Listview...Overdrive
Bless your soul! This is exactly what I needed!Arlberg
This works but shrinkWrap: true makes the page not scrollable.Wanderjahr
This didn't work for me and the logic you used to achieve this result is absolutely not clear, please add some comments.Incipit
in iOS you can still scroll, and it looks badWinebibber
A
68

Solving this question with shrinkWrap = true is a hack. The whole point of centering widgets inside a ListView is to have bounciness and scrolling enabled. Using shrinkWrap doesn't achieve this, it looks visually correct but it behaves completely wrong.

The solution is to place a Container as the only children in the ListView, and give it a minimum height equal to the available space for the height (Use LayoutBuilder to measure the maximum height for the widget). Then as the Container's child, you can either place a Center or Column (with MainAxisAlignment.center) widget and from there you can add whatever widgets you intended to center.

Below is the code to solve the example in the question:

Scaffold(
  appBar: AppBar(),
  body: LayoutBuilder(
    builder: (context, constraints) => ListView(
      children: [
        Container(
          padding: const EdgeInsets.all(20.0),
          constraints: BoxConstraints(
            minHeight: constraints.maxHeight,
          ),
          child: Center(
            child: Text('ABC'),
          ),
        )
      ],
    ),
  ),
);
Apfelstadt answered 14/8, 2020 at 19:18 Comment(10)
This is the best answer, shrinkWrap probably isn't what you want to use, although ideally ListView should have a better way to implement this. For my cases specifically, I need a ListView so that I can trigger a RefreshIndicator. Thanks.Indolent
@Indolent thanks for the nice words. i just updated my answer to be way cleaner and easier to understand. i hope you like it!Apfelstadt
In my case, this is the only working solution. I need a menu on top of the listview, and activityIndicator on the center. Thanx.Sacramentarian
Nice solution, unless you are working on a login/registration form (like me). There you will notice that the keyboard will close immediately after being opened. This problem doesn't happen with shrinkView: true. Using the keyboard is the only thing that forces me to use ListView instead of Column.Strother
@HamzaAbbad, I found that bug happening to me too, but has nothing to do with centering using a ListView. The bug is related with AutofillGroup on iOS. If you take AutofillGroup out, then the keyboard should work properly. Still waiting for the flutter to release a fix.Apfelstadt
THANK YOU! This was driving me nuts, and now that I see how to do it I am face-palming that I didn't think of it before.Apriorism
You may want use shrinkwrap: true,, just remember that doing that you need to also set the desired physics property.Maxi
I'd like to add that in addition to optionally using Column with MainAxisAlign.center, it is also possible to simulate a traditional full screen interface using MainAxisAlign.spaceBetween too to put a title at the top edge and buttons at the bottom edge, while also allowing the screen the scroll if overflowed.Afterthought
Works like charm! but had to set the mainAxisSize of the column to mainAxisSize.max for this solution to work for my use caseLockard
this should be the right questionProper
K
23

Wrap your widget into container

Container(alignment: Alignment.center, ...)

or

Container(alignment: Alignment.centerLeft, ...)
Krouse answered 25/10, 2018 at 14:52 Comment(0)
C
13

enter image description here


Simply wrap your widget in Align and provide alignment accordingly.

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView( // your ListView
        children: <Widget>[
          Align(
            alignment: Alignment.centerLeft,
            child: _button("Left"),
          ),
          Align(
            alignment: Alignment.center,
            child: _button("Middle"),
          ),
          Align(
            alignment: Alignment.centerRight,
            child: _button("Right"),
          ),
        ],
      ),
    );
  }

  Widget _button(text) => RaisedButton(onPressed: () {}, child: Text(text));
}
Crescen answered 29/2, 2020 at 8:39 Comment(0)
J
12

Use Align inside your ListView which will render Widgets at the center, Also we don't have to give any alignment property as by default it is center

This will add ListView at the center of the screen, as the list item increases it will grow from the center only.

   Center(
        child: ListView.builder(
          shrinkWrap: true,
          scrollDirection: Axis.vertical, // Axis.horizontal for horizontal list view.
          itemCount: 2,
          itemBuilder: (ctx, index) {
            return Align(child: Text('Text'));
          },
        ),
      ),

Output:

enter image description here

Jasminejason answered 29/6, 2020 at 16:38 Comment(4)
First you don't need to use Center as parent for your ListView, second scrollDirection is vertical by default, third, I have already provided Align as a solution to center the widget. I don't see any value in your answer and thus it should be deleted, correct me if I am wrong.Crescen
@CopsOnRoad: It will draw ListView from the center of the screen, I know the question is about widget under listview. This is another way where add Listview at the center as well as child TextJasminejason
So, you only want to add Center to your ListView for the question, right? Well even then you're not correct, no matter if you wrap your ListView inside Center or not, it won't make any difference. So, your answer actually carries no meaning. Correct me again if I am wrong.Crescen
it did center the widget, but listview still not scrollableNitroso
K
4

The simplest and most elegant way would be to use ClampingScrollPhysics, so the content is only scrollable if needed. Example:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ListView(
          physics: const ClampingScrollPhysics(),
            shrinkWrap: true,
            padding: const EdgeInsets.all(24),
            children: <Widget>[
.... your list of widgets ...
            ],
        ),
      ),
    );
  }
Kravits answered 3/8, 2023 at 10:38 Comment(1)
@daibaku please mark as accepted answer if this answers your issue 👌🏻Kravits
A
2

Just use the Align widget to center a child widget vertically and/or horizontally:

   Align(
    alignment: Alignment.center,
    child: Text(
      'middle',
    ),

Note: if you have a column as a child, you will have to add :

mainAxisAlignment: MainAxisAlignment.center 

to the column to align it vertically.

Amphistylar answered 3/5, 2020 at 15:19 Comment(0)
B
0

If you need the item in the center to scroll then do the following.

Center(
  child: ListView(
    shrinkWrap: true,
    children: [
      // the container with height will make the screen scroll
      Container(
        height:
             MediaQuery.of(context).size.height / 1.2,
        child: Text('ABC'),
      ),
    ],
  ),
),

Tip: give the container a color to visualize the areas that can scroll

Bairam answered 15/10, 2020 at 19:20 Comment(0)
S
0
    child: ListView.builder(
                      shrinkWrap: true,
                      itemCount: Doctor.listOfDoctors.length,
                      itemBuilder: (BuildContext context, int index) {
                        String name = Doctor.listOfDoctors[index].name;
                        String details = Doctor.listOfDoctors[index].info;
                        //better for design is to use ListTile instead of Text Widget
                        return ListTile(
                          title: Text(
                            name,
//this is how I solved this issue ;)
                            **textAlign: TextAlign.center,**
                          ),
Stylographic answered 20/11, 2022 at 6:23 Comment(0)
S
0

You can use CustomScrollView and SliverFillRemaining instead of using ListView.

Scaffold(
  appBar: AppBar(),
  body: CustomScrollView(
    slivers: [
      SliverFillRemaining(
        hasScrollBody: false,
        child: Center(
          child: new Text('ABC')
        ),
      ),
    ]
  )
);
Spirula answered 15/2 at 16:14 Comment(0)
A
-1

Add this container in your listview

Container(
            height: MediaQuery.of(context).size.height / 1.2,
            child: Center(
              child: Text(
                "No Record Found",
                style: TextStyle(fontSize: 20, color: Colors.black),
              ),
            ),
          ),
Appressed answered 5/4, 2022 at 6:3 Comment(0)
K
-2
    Scaffold(
      backgroundColor: Color.fromARGB(255, 238, 237, 237),
      body: Center(
        child: Container(
          child: Column(
            children: <Widget>[
              Column(children: <Widget>[
                Image.asset(
                  'images/logo.png',
                  fit: BoxFit.contain,
                  width: 130,
                )
              ]),
              Column(children: <Widget>[
                RaisedButton(
                  onPressed: () => {},
                  child: TextStyle_Title(
                    text: 'سلاااام',
                  ),
                )
              ]),
            ],
          ),
        ),
      ),
    )
Klug answered 6/10, 2021 at 11:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.