24

Is it possible to use ListView.builder (or something similar) inside of a CustomScrollView? I have a CustomScrollView like this:

return Scaffold(
  body: CustomScrollView(
    slivers: [
      SliverAppBar(...),
      SliverList(delegate: SliverChildListDelegate(children))
    ],
  ),
);

This works great, but in my actual scenario the list could have thousands of items, so I do not want to pass them all in to SliverChildListDelegate. I want to use ListView.builder (or something similar) to build the items as they are scrolled into view. I was expecting there to be a .builder constructor on either SliverList or SliverChildListDelegate but I don't see anything like that. Am I missing something?

Jordan Nelson
  • 1,162
  • 2
  • 8
  • 9

4 Answers4

34

The delegate argument of SliverList is not necessarily a SliverChildListDelegate.

You can also use SliverChildBuilderDelegate to achieve the builder effect of ListView.builder

SliverList(delegate: SliverChildBuilderDelegate((context, index) {
  return Container();
}));
Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • I am using SilverBuilderDelegate but still scrolling not working. I have raised a questions. https://stackoverflow.com/questions/62437049/flutter-pull-to-refresh-not-working-with-listview-builder – Roxx Jun 18 '20 at 03:02
  • 1
    The child count needs to be added... so delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return ...; }, childCount: ...length, ), – serg Nov 25 '20 at 06:52
31

I'm not sure how it is done in CustomScrollView but you can try this:

Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(...),
          ];
        },
        body: ListView.builder(..),)
);
Hussein Abdallah
  • 1,452
  • 11
  • 13
  • 1
    You made my day. I struggled to convert ListView into Slivers to hide the page title when scrolling until I found your solution using `NestedScrollView` with `headerSliverBuilder`. Thank you very much. – Tuan van Duong Dec 05 '20 at 10:53
9

You can use List.generate as example below

return Scaffold(
 body: CustomScrollView(
    slivers: [
      SliverAppBar(...),
      SliverList(delegate: SliverChildListDelegate(
          List.generate(yourList.length, (idx) {
                return Padding(
                  padding: const EdgeInsets.only(left: 8.0, right: 8.0),
                  child: Card(
                    child: ListTile(
                      leading: Icon(null),
                      title: Text(yourList[idx]),
                      onTap: null,
                    ),
                  ),
                );
              })
      ))
    ],
  ),
);
Saad Lembarki
  • 482
  • 5
  • 6
  • 3
    In addition to the code you've provided, consider giving a summary as to why this solves the issue. – jtate Oct 25 '19 at 22:11
2

This worked for me and I can have a SliverAppBar

return CustomScrollView(
      slivers: [
        SliverAppBar(
        ),
        SliverList(
            delegate: SliverChildListDelegate([
          SingleChildScrollView(
            child: Column(
              children: [
                Container(
                  child: ListView.builder(
                    shrinkWrap: true,
                    physics: NeverScrollableScrollPhysics(),
                    itemBuilder: (BuildContext context, int index) {

                    }
                  ),
                ),
              ],
            ),
          )
        ]))
      ],
    );
Luisfayre
  • 403
  • 4
  • 5
  • 7
    using ```shrink wrap``` will have serious performance issues for huge lists. https://www.youtube.com/watch?v=LUqDNnv_dh0 – Nithin Sai Dec 01 '21 at 16:03
  • 1
    For everyone else coming here: You can safely use `shrinkWrap: true` if you have ~2-4 widgets to render, but i totally agree with Nithin Sai that it will drastically cause performance issues and possible memory issues (if you render e.g. many images). – Marwin Lebensky Jun 07 '22 at 09:20