Features
- using
jumpToIndex
andanimateToIndex
to scroll to the specificindex
- No breaking for your current sliver widgets, e.g.,
ListView
/GridView
,SliverList
/SliverGrid
/SliverAppBar
- support almost official
RenderSliver
that has single child or multi children





Getting started
Use ScrollController
- create a
ScrollObserver
final ScrollController _controller = ScrollController();
late final ScrollObserver _observer =
ScrollObserver.multiChild(itemCount: _itemCount);
- bind
ScrollObserver
with the item widget/builder that must be wrapped byObserverProxy
ListView.builder(
controller: _controller,
itemBuilder: (context, index) => ObserverProxy(
observer: _observer,
child: ListTile(
key: ValueKey<int>(index),
leading: const CircleAvatar(
child: Text("L"),
),
title: Text("Positioned List Example $index"),
),
),
itemCount: _itemCount,
);
- use
jumpToIndex
/animateToIndex
_observer.jumpToIndex(
index,
position: _controller.position,
);
_observer.animateToIndex(
index,
position: _controller.position,
duration: const Duration(milliseconds: 200),
curve: Curves.fastLinearToSlowEaseIn,
);
There you go
Use PositionedScrollController
for ListView
that only has a single RenderSliver
- create
PositionedScrollController
final PositionedScrollController _controller =
PositionedScrollController.singleObserver();
- bind
ScrollObserver
to item widget/builder
ListView.builder(
controller: _controller,
itemBuilder: (context, index) => ObserverProxy(
observer: _controller.createOrObtainObserver(
itemCount: _itemCount,
),
child: ListTile(
key: ValueKey<int>(index),
leading: const CircleAvatar(
child: Text("L"),
),
title: Text("Positioned List Example $index"),
),
),
itemCount: _itemCount,
);
- use
jumpToIndex
/animateToIndex
_controller.jumpToIndex(index);
_controller.animateToIndex(
index,
duration: const Duration(milliseconds: 200),
curve: Curves.fastLinearToSlowEaseIn,
);
There you go
For
ListView.custom
andGridView.custom
, you could also usePositionedChildListDelegate
andPositionedChildBuilderDelegate
for wrapping items inObserverProxy
conveniently
Usage
- The item widget/builder must be wrapped using
ObserverProxy
ScrollObserver
would observe all children for slivers, e.g.,SliverList
/SliverGrid
, so all items should have the sameScrollObserver
instead of creating a differentScrollObserver
for each item.
Observing a single sliver
-
if you want to use
ScrollController
directly, you could create a standaloneScrollObserver
by using:ScrollObserver.singleChild
for a sliver with a single child, such asSliverAppBar
ScrollObserver.multiChild
for a sliver with multi children, such asSliverList
/SliverGrid
-
if you prefer using
PositionedScrollController
that would manageScrollObserver
created by you, you could create a controller byPositionedScrollController.singleObserver
. Then, you could create a standaloneScrollObserver
by using:PositionedScrollController.createOrObtainObserver
:hasMultiChild
indicates if this observer is for a sliver with multi children
Observing multiple slivers (typically for CustomScrollView
that has multiple slivers)
-
if using
ScrollController
, you have to create multipleScrollObserver
s manually and bind them to different slivers. Each sliver should have an uniqueScrollObserver
that must adopt its type: single child or multi children -
if using
PositionedScrollController
, you could createPositionedScrollController.multiObserver
to manage multipleScrollObserver
s automatically. Then, usingPositionedScrollController.createOrObtainObserver
to create a correspondingScrollObserver
for each sliver.
PositionedScrollController
It has all methods of ScrollController
by extends ScrollController
and then help you to manage ScrollObserver
.
-
PositionedScrollController.singleObserver
manage only a singleScrollObserver
that may have single child or multi children -
PositionedScrollController.multiObserver
manage multipleScrollObserver
that may have single child or multi children -
createOrObtainObserver
parameter | required | default | description |
---|---|---|---|
hasMultiChild | YES | true | determine if the ScrollObserver is for a sliver that has multi children |
itemCount | No | null | the sliver's item count. if null, the observer would behave as a infinite scroll view |
maxTraceCount | NO | null | the maximum count when tracing ObserverProxy 's ancestor RenderSliver and ParentData . Default to 50 internally, only setting it when you ensure you need to trace more nodes. |
targetToRenderIndex | NO | null | sometimes, the target index to which users want to scroll may not be same as the current render index. By using targetToRenderIndex , users could define how to map the target index to a render index, e.g., ListView.separated /ReorderableListView . Users could set it on an instance of ScrollObserver not only when creating it. Setting it only when you ensure you need it. |
renderToTargetIndex | NO | null | same as targetToRenderIndex but in converting reversely. |
jumpToIndex
andanimateToIndex
. (should passduration
andCurve
if usinganimateToIndex
)
parameter | required | default | description |
---|---|---|---|
index | YES | N/A | the item's index for a sliver. No effects if ScrollObserver.hasMultiChild is false |
whichObserver | NO | null | the specific ScrollObserver that is observing a sliver. It is required if ScrollObserver.hasMultiChild is true |
closeToEdge | YES | true |
try to scroll index at the leading edge if not over scrolling; otherwise, only ensure the index is visible on the screen. |
isVisible
: check if the given index is painted on the screen.
parameter | required | default | description |
---|---|---|---|
index | YES | N/A | the specify index you want to check visibility |
whichObserver | NO | null | the associated ScrollObserver with the index . Required if the controller is PositionedScrollController.multiObserver |
ScrollObserver
-
ScrollObserver.multiChild
: create aScrollObserver
that observes aRenderSliver
with multi children -
ScrollObserver.singleChild
: create aScrollObserver
that observes aRenderSliver
with a single child -
jumpToIndex
andanimateToIndex
. (should passduration
andCurve
if usinganimateToIndex
)
parameter | required | default | description |
---|---|---|---|
index | YES | N/A | the item's index for a sliver. No effects if ScrollObserver.hasMultiChild is false |
closeToEdge | YES | true |
try to scroll index at the leading edge if not over scrolling; otherwise, only ensure the index is visible on the screen. |
position | YES | N/A | the ScrollPosition attached to a ScrollController |