Features
- using
jumpToIndexandanimateToIndexto scroll to the specificindex - No breaking for your current sliver widgets, e.g.,
ListView/GridView,SliverList/SliverGrid/SliverAppBar - support almost official
RenderSliverthat 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
ScrollObserverwith 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
ScrollObserverto 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.customandGridView.custom, you could also usePositionedChildListDelegateandPositionedChildBuilderDelegatefor wrapping items inObserverProxyconveniently
Usage
- The item widget/builder must be wrapped using
ObserverProxy ScrollObserverwould observe all children for slivers, e.g.,SliverList/SliverGrid, so all items should have the sameScrollObserverinstead of creating a differentScrollObserverfor each item.
Observing a single sliver
-
if you want to use
ScrollControllerdirectly, you could create a standaloneScrollObserverby using:ScrollObserver.singleChildfor a sliver with a single child, such asSliverAppBarScrollObserver.multiChildfor a sliver with multi children, such asSliverList/SliverGrid
-
if you prefer using
PositionedScrollControllerthat would manageScrollObservercreated by you, you could create a controller byPositionedScrollController.singleObserver. Then, you could create a standaloneScrollObserverby using:PositionedScrollController.createOrObtainObserver:hasMultiChildindicates 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 multipleScrollObservers manually and bind them to different slivers. Each sliver should have an uniqueScrollObserverthat must adopt its type: single child or multi children -
if using
PositionedScrollController, you could createPositionedScrollController.multiObserverto manage multipleScrollObservers automatically. Then, usingPositionedScrollController.createOrObtainObserverto create a correspondingScrollObserverfor each sliver.
PositionedScrollController
It has all methods of ScrollController by extends ScrollController and then help you to manage ScrollObserver.
-
PositionedScrollController.singleObservermanage only a singleScrollObserverthat may have single child or multi children -
PositionedScrollController.multiObservermanage multipleScrollObserverthat 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. |
jumpToIndexandanimateToIndex. (should passdurationandCurveif 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 aScrollObserverthat observes aRenderSliverwith multi children -
ScrollObserver.singleChild: create aScrollObserverthat observes aRenderSliverwith a single child -
jumpToIndexandanimateToIndex. (should passdurationandCurveif 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 |