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');
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With