Synchronize the scrolling of your ListViews in Flutter
In my current project, I have a requirement where I display multiple ListView
s below each other and these lists must scroll together. It does not matter which list is scrolled by the user, the other one should follow it.
You can use ScrollController
when you want to manage the scrolling of a ListView
.
My first idea was to use the same controller for each list, but that won't work, it will not update the list that is not scrolled.
Another option would be to implement the synchronization by listening to changes on the controllers. But there is a great package that could help us and it is made by Google developers, the linked_scroll_controller.
Let's see how we can use it.
Let's say we have 2 horizontal list views below each other.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Awesome list 1'),
SizedBox(
height: 150,
// First list
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => _ListItem(
index: index,
),
),
),
const Divider(),
const Text('Awesome list 2'),
SizedBox(
height: 150,
// Second list
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => _ListItem(
index: index,
),
),
),
],
),
),
);
}
}
class _ListItem extends StatelessWidget {
const _ListItem({
Key? key,
required this.index,
}) : super(key: key);
final int index;
@override
Widget build(BuildContext context) {
return Card(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text('List item $index'),
),
),
);
}
}
This is how it looks like
Let's synchronize our lists.
First we need to add linked_scroll_controller to our dependencies in pubspec.yaml
:
dependencies:
linked_scroll_controller: ^0.2.0
Then we need to create the scroll controller group, which will manage the synchronization for us.
class _MyHomePageState extends State<MyHomePage> {
// Create a new scoll controller group
late final LinkedScrollControllerGroup _controllerGroup =
LinkedScrollControllerGroup();
// Create 2 new scroll controllers in the group, so they are connected.
late final ScrollController _controller1 = _controllerGroup.addAndGet();
late final ScrollController _controller2 = _controllerGroup.addAndGet();
// ...
}
Then we just need to add the 2 controllers to our ListView
s.
// ...
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Awesome list 1'),
SizedBox(
height: 150,
child: ListView.builder(
// Use the controller
controller: _controller1,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => _ListItem(
index: index,
),
),
),
const Divider(),
const Text('Awesome list 2'),
SizedBox(
height: 150,
child: ListView.builder(
// Use the controller
controller: _controller2,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => _ListItem(
index: index,
),
),
),
],
),
// ...
This is how it works:
That's it!
You can find the source code at github.com/dtengeri/linked_list_views_example