Search code examples
flutterflutter-listview

ListView inside ListView is building all item at once


On my screen I need to display a ListView inside an other ListView. The screen can be summarized like this:

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Isolate FutureBuilder Example'),
        ),
        body: Column(
          children: [
            Text("Header"),
            SizedBox(height: 16),
            Text("Filters"),
            SizedBox(height: 32),
            Expanded(
              child: ListView.builder(
                itemCount: 3,
                itemBuilder: (context, index) {
                  return Column(
                    children: [
                      Text("List $index"),
                      SizedBox(height: 32),
                      ListView.builder(
                          shrinkWrap: true,
                          physics: const ClampingScrollPhysics(),
                          itemCount: 50,
                          itemBuilder: (context, index) {
                            print("building $index");
                            return Text("$index");
                          })
                    ],
                  );
                },
              ),
            )
          ],
        ));
  }

If you try it, you will se that all the 200 items of the inner ListView.builder are built immediately, causing an UI jam in my main app since I have many more and more complex items.

How can I prevent this and keep the ListView behavior that builds only the visible items? I read that shrinkWrap: true can be the cause, but if I set it to false I have an error Vertical viewport was given unbounded height. and I am not able to fix it


Solution

  • You can try this code

    return Scaffold(
          appBar: AppBar(
            title: const Text('Isolate FutureBuilder Example'),
          ),
          body: CustomScrollView(
            physics: const ClampingScrollPhysics(),
            slivers: [
              const SliverAppBar(
                title: Text('Isolate FutureBuilder Example'),
              ),
              const SliverToBoxAdapter(
                child: Column(
                  children: [
                    Text("Header"),
                    SizedBox(height: 16),
                    Text("Filters"),
                    SizedBox(height: 32),
                  ],
                ),
              ),
              ...Iterable.generate(3, (index) {
                return [
                  SliverToBoxAdapter(
                    child: Column(
                      children: [
                        Text("List $index"),
                        const SizedBox(height: 32),
                      ],
                    ),
                  ),
                  SliverList.builder(
                    itemBuilder: (context, index) {
                      print("building $index");
                      return Text("$index");
                    },
                    itemCount: 50,
                  )
                ];
              }).toList().expand((element) => element).toList()
            ],
          ),
        );
      }
    

    here the nested list view is broken into flat listview using CustomScrollView and Slivers.