I add the two listviews builder in pageViewbuilder, the two listviews are separetly scrollable,but I want that the both listviews are scrollable in simultaneously in flutter
I add the two listviews builder in pageViewbuilder, the two listviews are separetly scrollable,but I want that the both listviews are scrollable in simultaneously in flutter
The solution is to synchronize the scroll between two ListViews by listening to scroll events with NotificationListener<ScrollNotification>. Whenever a scroll event is emitted from one ListView set the other ListView controller to jump to the same position.
One optimization is to ignore notifications on the other ListView if the first or second one is already scrolling. But it also works without this optimization.
This is the result (Check also out the live demo on DartPad).
Sources:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State createState() => _MyHomePageState();
}
enum ScrollingList {
none,
left,
right,
}
class _MyHomePageState extends State {
late final ScrollController _controllerLeft;
late final ScrollController _controllerRight;
var scrollingList = ScrollingList.none;
@override
void initState() {
super.initState();
_controllerLeft = ScrollController();
_controllerRight = ScrollController();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollStartNotification) {
if (scrollingList == ScrollingList.none) {
scrollingList = ScrollingList.left;
}
} else if (notification is ScrollEndNotification) {
if (scrollingList == ScrollingList.left) {
scrollingList = ScrollingList.none;
}
}
if (scrollingList == ScrollingList.left) {
_controllerRight.jumpTo(_controllerLeft.offset);
}
return true;
},
child: ListView.separated(
controller: _controllerLeft,
itemBuilder: (context, index) {
return Text('Item a$index');
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 100,
),
),
),
const VerticalDivider(),
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollStartNotification) {
if (scrollingList == ScrollingList.none) {
scrollingList = ScrollingList.right;
}
} else if (notification is ScrollEndNotification) {
if (scrollingList == ScrollingList.right) {
scrollingList = ScrollingList.none;
}
}
if (scrollingList == ScrollingList.right) {
_controllerLeft.jumpTo(_controllerRight.offset);
}
return true;
},
child: ListView.separated(
controller: _controllerRight,
itemBuilder: (context, index) {
return Text('Item b$index');
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 100,
),
),
),
],
),
);
}
}