Open yasinarik opened 4 years ago
Currently, I have just found a hacky solution
myself. I tried changing the cacheExtend
property of the Horizontal ListView.builder().
This solved the issue. However, putting a cacheExtend is basically telling the horizontal ListView.builder not to dispose/kill the invisible columns. Indeed, .builder()
is used for render on-demand
. So I have basically turned ListView.builder() into a basic ListView.
The weird thing is that when I tried doing it without a builder, with the basic ListView to prevent killing the invisible columns, the out of sync issue still occurred.
If you just want to know how to add unique keys, can't you use, say, ValueKey<String>
s where the strings embeds row/column information? (I'm not familiar with using package:linked_scroll_controller
, so I don't actually know.)
@yasinarik I have the same problem. The visible rows are perfectly kept in sync, however as I scroll down, the elements are becoming out of sync UNTIL another manual scroll occurs. That's pretty disappointing. :( Increasing the cacheExtent
seems to work, although I think that it defeats the purpose of using ListView.builder (just as you said). Is there another solution to this problem?
@rbluethl Sorry to say that but I couldn’t find a solution for this so I just skipped it. I don’t render rows on demand. This is a loss. I don’t know if it’s an acceptable loss however.
At least there are a limited amount of rows in a data table I would ever need in my application.
I’m using the linker because I built (am building) a Google Spreadsheet like tool where you can resize and reorder columns individually. I’m just making sure that the extent cache property is set accordingly to the total scrollable column widths. Or you can just write an arbitrarily big number like 20000.
Sample code that can reproduce the problem probably would help a lot.
It would be great if there were an example on how to use linked_scroll_controller
with dynamically added ScrollController
s. It's pretty hard to figure out how to do it. Controllers that are added dynamically with ListView.builer
are getting totally out of sync. Somehow these controllers are not correctly synchronized.
I had this issue and the following error message on Fluter web while I was trying to resize the flutter web app: _LinkedScrollPosition cannot change controllers once created.
. To solve this you need to make sure your dinamic ListView does not try to update the LinkedScrollControllerGroup
during the build phase (make sure to create your dynamic controllers only once and re-use it). basically don't call _linkedScrollControllerGroup.addAndGet()
inside the build method.
Basically what the docs says is: for each scrollable ( your ListView
) you need to add a unique key to prevent the sync issue. Here is how you add a unique jey to a scrollable:
Expanded(
child: ListView.separated(
key: ObjectKey(data), // This is the custom key
controller: controller,
itemCount: data.length,
itemBuilder: (context, index) {
final item = data[index];
return _MessageListItem(item: item);
},
separatorBuilder: (context, index) {
return _CustomDivider();
},
),
)
Note that each ListView's key must be created with a different data!
Hi! This is not working for me... The rows still go out of sync when I scroll.
class _HomePageState extends State<HomePage> {
final controllerGroup = LinkedScrollControllerGroup();
List<ScrollController> scrollControllers;
int channelCount = 80;
@override
void initState() {
scrollControllers = List<ScrollController>(channelCount);
for (int i = 0; i < channelCount; i++) {
scrollControllers[i] = controllerGroup.addAndGet();
}
super.initState();
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: channelCount,
itemExtent: 38,
itemBuilder: (BuildContext context, int i) {
return ListView.builder(
key: Key('Test-$i'),
controller: scrollControllers[i],
itemCount: 100,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int i) {
return Container(
margin: EdgeInsets.all(4),
height: 30,
width: 100,
color: Colors.red,
);
},
);
},
);
}
}
Any news? We're still facing this issue.
Any update?
I had the same problem when creating something like custom datatable which has horizontally scrollable table rows. When I sorted the table, table rows and header were going out of sync. I solved the problem by creating the keys also in init method. I am not sure if this is related to the OP though.
Ok, I have the same problem when number of rows is higher than 18. Interestingly, it still doesn't work even when I set cacheExtend: 900000.0
.
Ok, I solved it by adding a controller to the vertical listview bilder.
_verticalListController.addListener(() {
_linkedScrollControllerGroup.jumpTo(_linkedScrollControllerGroup.offset);
});
The package could have done this itself by jumping newly attached scrollers to the correct offset.
I had this issue and the following error message on Fluter web while I was trying to resize the flutter web app:
_LinkedScrollPosition cannot change controllers once created.
. This solve this you need to make sure your dinamic ListView does not try to update theLinkedScrollControllerGroup
during the build phase (make sure to create your dynamic controllers only once and re-use it). basically don't call_linkedScrollControllerGroup.addAndGet()
inside the build method.Basically what the docs says is: for each scrollable ( your
ListView
) you need to add a unique key to prevent the sync issue. Here is how you add a unique jey to a scrollable:Expanded( child: ListView.separated( key: ObjectKey(data), // This is the custom key controller: controller, itemCount: data.length, itemBuilder: (context, index) { final item = data[index]; return _MessageListItem(item: item); }, separatorBuilder: (context, index) { return _CustomDivider(); }, ), )
Note that each ListView's key must be created with a different data!
This worked for me
Ok, I solved it by adding a controller to the vertical listview bilder.
_verticalListController.addListener(() { _linkedScrollControllerGroup.jumpTo(_linkedScrollControllerGroup.offset); });
The package could have done this itself by jumping newly attached scrollers to the correct offset.
This must be the most appropriate solution!
One caveat, though. In some cases _linkedScrollControllerGroup.offset
was instantly updated to the wrong value, so the feature was still broken for me.
I've solved this issue by not directly using the _linkedScrollControllerGroup.offset
but rather by setting a "temp" variable to the horizontal offset and using that value to jump to subsequently. Example:
// ...
double _horizontalScrollOffset = 0;
@override
void initState() {
super.initState();
// setting the horizontal offset to the "temp" variable
_horizontalScrollControllersGroup = LinkedScrollControllerGroup()..addOffsetChangedListener(() {
_horizontalScrollOffset = _horizontalScrollControllersGroup.offset;
});
// jumping to that offset when scrolling vertically
_verticalScrollController = ScrollController()
..addListener(() {
_horizontalScrollControllersGroup.jumpTo(_horizontalScrollOffset);
});
// ...
}
// ...
I have been building a custom data table widget for FlutterWeb use in particular. It can be scrolled in both directions. There is a single ListView.builder (for horizontal scrolling) and it holds dynamically added ListView.builders (for vertical scrolling as columns).
I've just figured out that the vertical scrollers go out of sync, unfortunately. It happens when some vertical ListView.builders are out of the visible area.
As I said, I can scroll horizontally. For example, 0-1-2-3-4 columns are visible. I scroll down to an arbitrary point such as somewhere near the 250th row. Then I scroll to right to see the 3-4-5-6 columns. The columns 5-6 were invisible until I scroll. At that moment they are out of sync.
If I then scroll up or down they become in sync immediately.
How can I solve that?