Can't set ListView into LayoutBuilder Widget (Flutter)

Viewed 3944

I need to have some structure like this

enter image description here

I use LayoutBuilder to get the height of content (between App Bar and TabsBottomNavigation). Here i build Profile Info Container and want to build ListView with some List Tiles, but when I try to build it in Layout Builder I have errors in console.

enter image description here

If I create ListView out of LayoutBuilder it works!

Please help me to solve it. My code below:

Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
        return SingleChildScrollView(
          child: Container(
            child: Column(
              children: <Widget>[
                Container(
                  height: viewportConstraints.maxHeight * .44,
                  color: Theme.of(context).primaryColor,
                  padding: EdgeInsets.only(bottom: 2),
                  child: Align(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        _buildProfileImage(context),
                        SizedBox(height: 17),
                        Text(userName)
                      ],
                    ),
                  ),
                ),
                Expanded(
                  child: ListView(
                    children: <Widget>[
                      ListTile(
                        leading: Icon(Icons.print),
                        title: Text('asdad'),
                      )
                    ],
                  ),
                )
              ],
            ),
          ),
        );
      },
    );
  }
5 Answers

Use below build method will work in your case. (I have checked and it's working, so I hope it will work in your case also and will fit in your requirement.)

Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
        return Container(
          child: Column(
            children: <Widget>[
              Container(
                height: viewportConstraints.maxHeight * .44,
                color: Theme.of(context).primaryColor,
                padding: EdgeInsets.only(bottom: 2),
                child: Align(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      _buildProfileImage(context),
                      SizedBox(height: 17),
                      Text(userName),
                    ],
                  ),
                ),
              ),
              SizedBox(height: 16),
              Flexible(
                child: ListView(
                  children: <Widget>[
                    Card(
                      child: ListTile(
                        leading: Icon(Icons.print),
                        title: Text('asdad'),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
  }

I think SingleChildScrollView is of no use in this case so I removed it but you can use it if you fill so.

You still need to do some UI improvement as per your wish as this is the basic structure as per your requirement.

Hope this will help you.

You are using the LayoutBuilder in a wrong way.
It's supposed to be used to change the layout with the size of the device and/or orientation.

What you are trying to do is best accomplished with MediaQuery:

MediaQuery.of(context).padding.top //APP bar height
MediaQuery.of(context).padding.bottom //Bottom bar height
MediaQuery.of(context).size.height //Screen height
Widget build(BuildContext context) {
return Column(
    children:<Widget>[
     Expanded(
      child:LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
        return SingleChildScrollView(
          child: Container(
            child: Column(
              children: <Widget>[
                Container(
                  height: viewportConstraints.maxHeight * .44,
                  color: Theme.of(context).primaryColor,
                  padding: EdgeInsets.only(bottom: 2),
                  child: Align(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        _buildProfileImage(context),
                        SizedBox(height: 17),
                        Text(userName)
                      ],
                    ),
                  ),
                ),
                Expanded(
                  child: ListView(
                    children: <Widget>[
                      ListTile(
                        leading: Icon(Icons.print),
                        title: Text('asdad'),
                      )
                    ],
                  ),
                )
              ],
            ),
          ),
        );
      },
    ),
  ),
 ]
);
}
 Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
        return SingleChildScrollView(
          child: ListView(
            shrinkWrap: true,
            children: <Widget>[
             new Container(
                height: MediaQuery.of(context).size.height/3,
                color: Theme.of(context).primaryColor,
                padding: EdgeInsets.only(bottom: 2),
                child: Align(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      _buildProfileImage(context),
                      SizedBox(height: 17),
                      Text(userName)
                    ],
                  ),
                ),
              ),
             new ListView(
                shrinkWrap: true,
                children: <Widget>[
                  ListTile(
                    leading: Icon(Icons.print),
                    title: Text('asdad'),
                  )
                ],
              )
            ],
          ),
        );
      },
    );
  }

If you read the error log, it says non-zero flex incoming but constraints are unbounded. To understand that clearly, imagine Flutter is trying to draw pixels of something that not finite. That's the our problem.

Widgets like ListView or SingleChildScrollView are flex widgets and has no limits unlike Column or Row.

If you have children that sizes are not definite, then you have to define flex for your ListView. For that, you can use shrinkWrap or Flexible, Expanded widgets for both ListView itself or children.

And here is the my solution, simplified as much as possible:

Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
        return ListView(
          shrinkWrap: true, // That's it
          children: <Widget>[
            Container(
              color: Theme.of(context).primaryColor,
              height: viewportConstraints.maxHeight * .44,
              padding: EdgeInsets.only(bottom: 2),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  _buildProfileImage(context),
                  SizedBox(height: 17),
                  Text(userName)
                ],
              ),
            ),
            ListTile(
              leading: Icon(Icons.print),
              title: Text('asdad'),
            ),
            ListTile(
              leading: Icon(Icons.print),
              title: Text('asdad'),
            ),
            ListTile(
              leading: Icon(Icons.print),
              title: Text('asdad'),
            )
          ],
        );
      },
    );
  }

Meanwhile, you have too many children that does nothing. If you want different scrolling behavior inside the Profile Info and ListTiles parts, tell me because we will must create yet another ListView for achieve that.

Also if you share your buildProfileImage widget, we can optimize your code even further, because you may even not need the LayoutBuilder widget in this case.

Related