86

I have a widget tree like this:

SingleChildScrollView
   Column
     Container
       ListView(or GridView)

the problem is that when my widget tree is like above, it gives me error of

NEEDS PAINT

so I change my widget tree like this:

Column
     Container
       ListView(or GridView)

but in this situation the ListView or GridView part scrolls separately, and I want the whole widget tree to scroll. how do you think I can achieve it?

geekymano
  • 1,420
  • 5
  • 22
  • 53

9 Answers9

161

You could use your first widget-tree and apply the following changes:

  1. In every ListView and GridView set shrinkWrap: true. This fixes the error message you were getting.
  2. In every ListView and GridView set physics: NeverScrollableScrollPhysics(). This disables the scroll on them and new you can only scroll on the SingleChildScrollView
Zvi Karp
  • 3,621
  • 3
  • 25
  • 40
  • 13
    please also note that by making `shrinkWrap: true` makes the `ListView` or `GridView` more expensive to build. see more: https://api.flutter.dev/flutter/widgets/ScrollView/shrinkWrap.html – dehamzah Nov 21 '19 at 22:18
72

As suggested by other answers, you can do that by setting shrinkWrap: true, physics: NeverScrollableScrollPhysics(), but building a shrinkwrapped listview is more expensive than building a normal listview, I think it will be a good idea to use a map() on the list.

Column(
  children: itemList.map((item) {
       return Text(item);
    }).toList()
),
Shabeer Ahammed
  • 173
  • 1
  • 1
  • 10
Sudeep Bashistha
  • 1,320
  • 12
  • 16
48

For me, setting primary to false and shrinkWrap to true worked.

ListView(
   primary: false,
   shrinkWrap: true,
),
Rakesh Verma
  • 766
  • 6
  • 14
33

Why it is happening?

It happens because Column and ListView both take the entire space of screen individually which is there default behavior.

How to solve the problem?

To solve the above problem we have to disable scrolling of Listview, This can be possible by shrinkWrap and physics property

shrinkWrap:true - It forces ListView to take only the required space, not the entire screen.

physics: NeverScrollableScrollPhysics() - It disables scrolling functionality of ListView, which means now we have only SingleChildScrollView who provide the scrolling functionality.

Code:

SingleChildScrollView
   Column
     Container
        ListView(
                shrinkWrap: true,
                physics: NeverScrollableScrollPhysics(),
                //...
                )

Note: Above ListView behaviour will be also applied for GridView.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Jitesh Mohite
  • 31,138
  • 12
  • 157
  • 147
  • This works fine but it prevents listview builder to create item widgets on demand. All items are created at once. Is there a solution for that? – Radhika Gokani May 10 '21 at 09:29
  • @RadhikaGokani: Could you please create a new question and paste it here, so that I can understand in detail. – Jitesh Mohite May 10 '21 at 09:48
  • https://stackoverflow.com/questions/67467737/listview-builder-inside-singlechildscrollview-prevents-widget-creation-on-demand @JiteshMohite – Radhika Gokani May 10 '21 at 09:54
  • Its not a solution. It will crop the nested widget. And you need it to take up the rest of the space. – localkostya Aug 28 '23 at 20:44
30

Set primary to false in your ListView.

ListView(
   primary: false,
),

That should prevent it from scrolling separately.

JideGuru
  • 7,102
  • 6
  • 26
  • 48
18

I am using nested Listviews and this helped me. Add these lines in all of your ListviewBuilders

ListView(
   shrinkWrap: true,
   primary: false,
),
CoderUni
  • 5,474
  • 7
  • 26
  • 58
  • 2
    its not a good idea to shrinkwrap all your listviews. ListView.builder builds it children lazily meaning that it will only build if the widget is on the user's screen. (Ex: when the user scrolls down) shrinkwrapping the listview will make the listviewbuilder build all its children all at once. – CoderUni Aug 30 '20 at 14:48
2

using this inside listview works fine for me.

physics: NeverScrollableScrollPhysics(),

shrinkWrap: true,
imran sifat
  • 165
  • 1
  • 13
0

This will work like a charm.

Column(
children: itemList.map((item) {
   return Text(item);
}).toList(),
),
Feisal Aswad
  • 365
  • 3
  • 9
0

I used the combination of all three (primary: false, shrinkWrap: true, physics: NeverScrollableScrollPhysics()) and it just worked:

   SingleChildScrollView(

      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            child: ListView.builder(primary: false, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: movies.length ,itemBuilder: (context, index) {
              Movie movie = movies[index];
              return Container(
                child: Card(
                  color: Colors.greenAccent,
                  key: ValueKey(movie.title),
                  child: ListTile(
                    title: Text(movie.title),
                    subtitle: Text(movie.duration),
                    trailing: IconButton(
                      icon: Icon(Icons.favorite),
                      color: movies[index].isFav ? Colors.red : Colors.white,
                      onPressed: () {
                        context.read<MovieProvider>().updateFav(!movies[index].isFav, movie);
                      },
                    ),
                  ),
                ),
              );
            }),
          )
        ],
      ),
    )
maddy
  • 4,001
  • 8
  • 42
  • 65