Flutter ListView.Builder() in scrollable Column with other widgets

I have a TabBarView() with an amount of different views. I want of them to be a Column with a TextField at top and a ListView.Builder() below, but both widgets should be in the same scrollable area (scrollview). The way I implemented it threw some errors:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder)
    ],
   );
}

Error:

I/flutter (23520): The following assertion was thrown during performResize():
I/flutter (23520): Vertical viewport was given unbounded height.
I/flutter (23520): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (23520): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (23520): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (23520): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (23520): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (23520): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (23520): the height of the viewport to the sum of the heights of its children.

I read about stacking the ListView.builder() in an Expanded-Area but it made the textfield kind of "sticky" which is not what I want. :-)

I also came across CustomScrollView but didn't fully understand how to implement it.


Here is the solution:

SingleChildScrollView(
        physics: ScrollPhysics(),
        child: Column(
          children: <Widget>[
             Text('Hey'),
             ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount:18,
                itemBuilder: (context,index){
                  return  Text('Some text');
                })
          ],
        ),
      ),

Placing the ListView inside an Expanded widget should solve your problem:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new Expanded(child: ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder))
    ],
   );
}

Use SingleChildScrollView which allows the child widget to scroll

Solution

SingleChildScrollView(
          child: Column(
            children: <Widget>[
                      ListView.builder(
                      shrinkWrap: true,
                      physics: NeverScrollableScrollPhysics(),

Two properties used here

shrinkWrap: true

only occupies the space it needs (it will still scroll when there more items).

physics: NeverScrollableScrollPhysics()

Scroll physics that does not allow the user to scroll. Means only Column+SingleChildScrollView Scrolling work.


Reason for the error:

Column expands to the maximum size in main axis direction (vertical axis), and so does the ListView

Solution

You need to constrain the height of the ListView, so that it does expand to match Column, there are several ways of solving this issue, I'm listing a few here:


  1. If you want to allow ListView to take up all remaining space inside Column use Flexible.

    Column(
      children: <Widget>[
        Flexible(
          child: ListView(...),
        )
      ],
    )
    

  1. If you want to limit your ListView to certain height, you can use SizedBox.

    Column(
      children: <Widget>[
        SizedBox(
          height: 200, // constrain height
          child: ListView(),
        )
      ],
    )
    

  1. If your ListView is small, you may try shrinkWrap property on it.

    Column(
      children: <Widget>[
        ListView(
          shrinkWrap: true, // use it
        )
      ],
    )
    

Use physics: NeverScrollableScrollPhysics() and shrinkWrap: true inside ListView.Builder() and enjoy