When I scroll through one List Wheel Scroll View, the other list either lags or does not scroll smoothly.
https://pub.dev/packages/linked_scroll_controller allows to sync lists but does not support FixedExtendScrollPhysics.
Output : –
https://pub.dev/packages/linked_scroll_controller works perfectly if we are using ScrollPhysics but throws an error when used with a widget that uses FixedExtendScrollPhysics. I want both the list to move Synchronizing that is if I move green list I want red list to move simultaneously and vice versa
Code :
import 'dart:math';
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 MaterialApp(
title: 'List',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const List(),
);
}
}
class List extends StatefulWidget {
const List({Key? key}) : super(key: key);
@override
_ListState createState() => _ListState();
}
class _ListState extends State<List> {
final scrollController = FixedExtentScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("List"),
backgroundColor: Colors.green,
),
body: Row(
children: [
SizedBox(
height: 600,
width: 300,
child: ListWheelScrollView(
itemExtent: 100,
physics: const FixedExtentScrollPhysics(),
onSelectedItemChanged: (value) {
setState(() {
scrollController.animateToItem(value,
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut);
});
},
children: [
for (int i = 0; i < 5; i++) ...[
Container(
color: Colors.green,
height: 50,
width: 50,
)
]
]),
),
SizedBox(
height: 600,
width: 300,
child: ListWheelScrollView(
controller: scrollController,
physics: const FixedExtentScrollPhysics(),
itemExtent: 100,
children: [
for (int i = 0; i < 5; i++) ...[
Container(
color: Colors.red,
height: 50,
width: 50,
)
]
]),
)
],
));
}
}
4
Answers
Try separate two
controller
and add listener like this:Really interesting question. The problem was syncing both the scrollviews. I made few changes to your code to achieve the desired result.
The basic idea is to remove listener to the other scroll before forcing pixels. After the scroll, add the same listener.
But because it happens instantaneously and actual scroll happens sometimes in future, they don’t overlap perfectly.So I had to introduce
CancelableCompleter
from the async library to make sure add operation does not happen if another scroll event had happened.With
forcePixels
, the scrolling to other wheel is not deferred hence CancelableCompleter is not required.I am using protective member function
forcePixels
as Flutter has not provided any way to set pixels without animation without creating subclass of ScrollPosition. If you are fine with this linter warning, it is all good. If not, we will have to extend ListWheelScrollView to use ScrollPosition where we could make changes as per need.Better Approach is to use linked_scroll_controller.
Scrolling widgets will create a default scroll controller (ScrollController class) if none is provided. A scroll controller creates a ScrollPosition to manage the state specific to an individual Scrollable widget.
To link our scroll controllers we’ll use linked_scroll_controller, a scroll controller that allows two or more scroll views to be in sync.
Now use these controllers on your listviews.
below are two nice examples which will help you to use linked_scroll_controller in your case.
Flutter: How to create linked scroll widgets
Flutter: Creating a two-direction scrolling table with a fixed head and column
Creating a two-direction scrolling with linked_scroll_controller