101

What is the preferred way to achieve a nested ListView, or in other words, ListView Widgets that could be included within a scrollable parent?

Imagine a "Reports" page, where a section is an itemized list.

0

9 Answers 9

275

For child ListView, use that parameter:

shrinkWrap: true,
physics: ClampingScrollPhysics(),
Sign up to request clarification or add additional context in comments.

10 Comments

This doesn't work for me when the child list view is nested in a scrollBar nested in a ScrollConfiguration nested in a Container
This works for the nested ListView that is inside of a parent ListView! Thanks!
Thanks, ClampingScrollPhysics() basically adds the length of the nested scrollbar to the entire screen. Very useful, thanks !
It only works for a specific case, like both parent and child listviews are just normal ListView(children: [...]). It fails for ListView.builder(...)
there is choppy scroll whent Listview => Listview.Builder
|
59

Adding physics: ClampingScrollPhysics() and shrinkWrap: true did the trick for me.

sample code:

@override
Widget build(BuildContext context) {
  return Container(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Expanded(
          child: ListView.builder(
              shrinkWrap: true,
              itemCount: 123,
              itemBuilder: (BuildContext context, int index) {
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Text('Parent'),
                    ListView.builder(
                        itemCount: 2,
                        physics: ClampingScrollPhysics(), 
                        shrinkWrap: true,
                        itemBuilder: (BuildContext context, int index) {
                          return Text('Child');
                        }),
                  ],
                );
              }),
        )
      ],
    ),
  );
}

Comments

31

If you want to have the inner ListView be scrollable independently of the main scroll view, you should use NestedScrollView. Otherwise, use a CustomScrollView.

Here is some code illustrating the NestedScrollView approach.

video

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            new SliverAppBar(
              pinned: true,
              title: new Text('Flutter Demo'),
            ),
          ];
        },
        body: new Column(
          children: <Widget>[
            new FlutterLogo(size: 100.0, colors: Colors.purple),
            new Container(
              height: 300.0,
              child: new ListView.builder(
                itemCount: 60,
                itemBuilder: (BuildContext context, int index) {
                  return new Text('Item $index');
                },
              ),
            ),
            new FlutterLogo(size: 100.0, colors: Colors.orange),
          ],
        ),
      ),
    );
  }
}

2 Comments

This does not scroll the Flutterlogo completly. It stops scrolling. How can I scroll the whole container? I mean that the FlutterLogo is completly invisible?
The "main" scroll, the Nested, does not scroll at all. Adding more logos at the end, resulted in overflow and not the expected scrolling. Hmm . . .
13

Screenshot:

enter image description here


Code:

var _container = Container(
  height: 200,
  color: Colors.blue,
  margin: EdgeInsets.symmetric(vertical: 10),
);

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text("ListView")),
    body: Padding(
      padding: const EdgeInsets.all(40.0),
      child: ListView( // parent ListView
        children: <Widget>[
          _container,
          _container,
          Container(
            height: 200, // give it a fixed height constraint
            color: Colors.teal,
            // child ListView
            child: ListView.builder(itemBuilder: (_, i) => ListTile(title: Text("Item ${i}"))),
          ),
          _container,
          _container,
          _container,
        ],
      ),
    ),
  );
}

3 Comments

Briliant! Trying to work around fixed height (eg let it expand if there is more room)
10 mins later: wrap inner ListView in ConstrainedBox (where specify min/max dims) and shrinkWrap inner list. Bam! Let's see if it works in production.
This is the only one that worked for me. I wonder if there is a way to not hardcode the height. Will try what @visoft tried
12

For inner Listview I have just added below code and it solved for me

shrinkWrap: true,
physics: ScrollPhysics(),

1 Comment

When the inner Listview becomes scrollable your code doesn't work.
10

Thanks to Serdar Polat:

ListView.builder( // outer ListView
  itemCount: 4,
  itemBuilder: (_, index) {
    return Column(
      children: [
        Container(
          color: Colors.blue,
          alignment: Alignment.center,
          child: Text('Header $index'),
        ),
        ListView.builder( // inner ListView
          shrinkWrap: true, // 1st add
          physics: ClampingScrollPhysics(), // 2nd add
          itemCount: 10,
          itemBuilder: (_, index) => ListTile(title: Text('Item $index')),
        )
      ],
    );
  },
)

Comments

4

shrinkWrap to wrap your content and ClampingScrollPhysics to use the parent scroll

ListView.builder(
    shrinkWrap: true,
    physics: const ClampingScrollPhysics(),
    itemCount: yourList.length,
    itemBuilder: (context, index) => YourWidget(items[index]),
),

Comments

2

I use this:

scrollController.addListener(onScroll);

void onScroll(){
    if(scrollController.offset == 0.0
        || scrollController.position.extentBefore == 0.0
        || scrollController.position.extentAfter == 0.0){
      scrollPhysics = NeverScrollableScrollPhysics();

      Future.delayed(Duration(seconds: 1), (){
        scrollPhysics = ClampingScrollPhysics();
        setState((){});
      });

      setState((){});;
    }
  }

1 Comment

Use AlwaysScrollableScrollPhysics instead of ClampingScrollPhysics.
0
 Expanded(
                  child: ListView.builder(
                      shrinkWrap: true,
                      padding: const EdgeInsets.all(8),
                      itemCount: requestList.length,

                      itemBuilder: (BuildContext context, int index) {
                        int que = index;
                        return Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Container(
                                padding: const EdgeInsets.only(
                                    left: 20,
                                    top: 10,
                                    bottom: 10,
                                    right: 20),
                                child: Text(
                                  '${que++} . ${requestList[index].question}',
                                  textAlign: TextAlign.center,
                                  style: TextStyle(
                                    fontSize: 14,
                                    color: HexColor(HexColor.black),
                                    fontFamily: 'montserrat_regular',
                                    decoration: TextDecoration.none,
                                  ),
                                )),
                            ListView.builder(
                                itemCount: requestList[index].questionOptions!.length,
                                physics: ClampingScrollPhysics(),
                                shrinkWrap: true,
                                itemBuilder: (BuildContext context, int subindex) {
                                  return Row(
                                    children: <Widget>[
                                      Radio(
                                          value: 1,
                                          groupValue: radio_value[index],
                                          onChanged: (values) async {
                                            setState(() {
                                              radio_value[index] = 1;
                                              qutionCheckModel[index].response =
                                              "yes";
                                            });
                                          }),
                                      Container(
                                        child: Text(
                                          requestList[index].questionOptions![subindex],
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            fontSize: 14,
                                            color: HexColor(HexColor.black),
                                            fontFamily: 'montserrat_regular',
                                            decoration: TextDecoration.none,
                                          ),
                                        ),
                                      ),

                                    ],
                                  );
                                }),
                          ],
                        );
                      }),
                ),

enter image description here

1 Comment

hey man. i'm looking at this code. In case i have a textfield with controller on the 2nd listview.builder. how do i make the controller unique for each entry? coz i can't do "controller: _controllertext[index][subindex].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.