Flutter: Continue scrolling in top Listview when reaching bottom of nested Listview
Asked Answered
I

1

5

I wish to create the following: when reaching the top or bottom of the inner Listview, I want to continue scrolling in the top Listview. See GIF:

Gif of what I got so far

An option would be to set the physics of the inner Listview to NeverScrollablePhysics when the bottom is reached (using a Listener to the controller) but then if you would want to scroll up again this wouldn't work.

See below for my code, thanks in advance!

class TestAppHomePage extends StatefulWidget {
@override
TestAppHomePageState createState() => new TestAppHomePageState();
}

class TestAppHomePageState extends State<TestAppHomePage> {


 ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    print('set up');
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Container(
        color: Colors.green,
        child: ListView(
          primary: false,
          // controller: _scrollController,
          children: <Widget>[topWidget(), topWidget(), topWidget(), topWidget()],
        ),
      ),
    );
  }

  Widget topWidget() {
    return Card(
        color: Colors.purple,
        margin: EdgeInsets.all(16),
        child: Container(
          height: 400,
          child: Column(
            children: <Widget>[
              Container(height: 100, color: Colors.white),
              Expanded(
                  child: ListView(
                      controller: _scrollController,
                      children: List.generate(
                        40,
                        (index) {
                          return someText(index);
                        },
                      ).toList()))
            ],
          ),
        ));
  }

  Widget someText(int i) {
    return Text('text no $i');
  }
}
Inkerman answered 11/12, 2019 at 21:42 Comment(3)
anyone solved this problem?Fenugreek
I need it also. If we set the shrinkWrap: true, It will breaking the reuse mechanism in ListView. Which will very slowly if the item count is huge.Favourable
Have a look at this answer: stackoverflow.com/a/60611242, solved it for meFrontogenesis
L
6

I work on the same project as OP, but because nobody has responded yet, I thought I would share my own fiddling, thought procesesses and what I have up to now. I will update this answer

First of all, I tried to prevent creating a solution with a lot of boiler-plate code, but I am afraid I have maybe gone a little bit too far in doing so. I am quite certain my solution is not correct, because the compiler gives me warnings.

Without any further ado, my thoughts were:
1. I needed a way to capture the input of the user in the inner list. therefore, it makes sense to create a custom ScrollPhysics.
2. It is important that the innerlist works normally in all cases. Therefore, it always calls super to handle that.
3. I needed to pass around a function that accepted the input I captured and pretended that exactly that input was passed into the outer list.

The Gif with the result

// imports and stuff..

class CustomScroll extends BouncingScrollPhysics { 
  final Function outerController;
  CustomScroll({this.outerController, ScrollPhysics parent}): super(parent: parent);
  @override
  CustomScroll applyTo(ScrollPhysics ancestor) {
    return CustomScroll(
        outerController: outerController,  parent: buildParent(ancestor));
  }
  @override 
  Simulation createBallisticSimulation(ScrollMetrics position, double velocity) {
    if (position.pixels >= position.maxScrollExtent && velocity >= 0.0) {
      outerController(velocity);
    }
    return super.createBallisticSimulation(position, velocity);
  }
}

class ListInAList extends StatefulWidget {
  createState() => ListInAListState();
}
class ListInAListState extends State<ListInAList> with TickerProviderStateMixin {
  List<ScrollController> innerControllers = List();
  ScrollController outerController = ScrollController();
  final outerPhysics = BouncingScrollPhysics();
  void innerListener(double velocity, ScrollController outerController)
  {

    final sim = outerPhysics.createBallisticSimulation(outerController.position, velocity);
    ScrollActivity _test = BallisticScrollActivity(outerController.position.activity.delegate,sim,this);
    if (_test != null)
    outerController.position.beginActivity(_test);

  }

  Widget build(BuildContext context) {
    return ListView.builder(
        itemBuilder: buildItem, controller: outerController, itemCount: 4, physics: outerPhysics);
  }

  Widget buildItem(BuildContext context, int index) {
    final innerController = ScrollController();
    innerControllers.add(innerController);

    return Column(children: [
      Container(height: 100, color: Colors.blue),
      ListView.builder(
        physics: CustomScroll(outerController: (velocity) => innerListener(velocity, outerController)),
        itemBuilder: buildLoremImpsum,
        controller: innerController,
        itemCount: 20),
    ]);
  }
  Widget buildLoremImpsum(context, index) {
    return Container(
        height: 30,
        color: (index % 2 == 0)
            ? Color.fromRGBO(255, 0, 0, 1)
            : Color.fromRGBO(255, 255, 0, 1));
  }
}

So, basically, only createBallisticSimulation and the function innerListener are the truly interesting parts of the code, everything else is just part of the example.

Lexie answered 17/12, 2019 at 22:55 Comment(1)
could you please post a full example ? i'm new in Flutter. Please!Portcullis

© 2022 - 2024 — McMap. All rights reserved.