I'm trying to create a desktop-style scrollbar, that changes it's size based on the size of the content. My scrollbar shares a ScrollController with a list, and relies on the position.maxExtents to know how large the content area is.
The issue is that when I change the number of rows, the maxExtents will not update, until a scrollEvent is initiated.
I've worked around it with code like this, moving 1px up, and 1px down over 100ms:
widget.controller.jumpTo(controller.position.pixels + 1);
Future.microtask(() => widget.controller.animateTo(controller.position.pixels - 1, duration: 100.milliseconds, curve: Curves.linear));
Which works pretty quite well when the list can scroll. However, when the list is < the height of the view, it can't scroll, and these calls have no effect, and I'm stuck with a stale maxExtents.
How can I just tell the list: "Hey, list, recalculate your children!"?
You can delay your code to when the controller has been updated using the following.
WidgetsBinding.instance.addPostFrameCallback((_) {
...your code which requires controller's max extents...
});
Aside from the issues you've mentioned, animating the scroll position will cause Flutter to draw frames unnecessarily.
Borrowing from @ltk and @Rakaton, I think there's a simpler and more efficient way to do this:
// Run this code whenever the layout changes (i.e. any time you setState
// to update the list content)
WidgetsBinding.instance?.addPostFrameCallback((_) {
widget.scrollController.position.notifyListeners();
});
You may also want to wrap your list component in a SizeChangedLayoutNotifier
to detect size changes from things like window resize:
NotificationListener<SizeChangedLayoutNotification>(
onNotification: (notification) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
scrollController.position.notifyListeners();
});
return true;
},
child: SizeChangedLayoutNotifier(
child: ListView(
// ...
),
),
);
I think you should consider to use force pixels, but it's a protected method so it's gonna give you a warning. And I don't know about the performance or another stuffs about it.
widget.controller.position.forcePixels(controller.position.pixels + 1);
or combination of correct pixels and notifylistener.
widget.controller.position.correctPixels(controller.position.pixels + 1);
widget.controller.position.notifyListeners();
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