-
Notifications
You must be signed in to change notification settings - Fork 29.7k
ScrollEndNotification example: auto-scroll based on RenderSliver constraints and geometry #143538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact "@test-exemption-reviewer" in the #hackers channel in Chat (don't just cc them here, they won't see it! Use Discord!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
5c78010 to
997da02
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels strange to me that we have to save a reference to the widget to use methods to get its sliver constraints, geometry, and/or whether or not it's been laid out. Would we be able to assign a key to the widget to access the same information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the key can be used to then look up info on the sliver registered with the coordinator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it is strange to squirrel away widget references and use them this way. I think the API is simpler for it, but it is a little off-putting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FTR, here's the current API with the tricky in-line assignment of the CoordinatedSliver variable. It avoids requiring a separate unique object to identify what's already a unique object (the CoordinateSliver itself). That said, the inline assignment might be too cute.
late CoordinatedSliver alignedItem;
SliverCoordinator(
callback: (ScrollNotification notifcation, SliverCoordinatorData data) {
if (notification is ScrollEndNotification && alignedItem.hasLayoutInfo(data)) {
...
}
},
child: CustomScrollView(
slivers: <Widget>[
alignedItem = CoordinatedSliver(
child: ...,
),
...
],
),
)Originally the API did require a unique ID per CoordinateSliver, which is a little more conventional. I could have used the CoordinatedSliver's key for the same purpose but wasn't comfortable with making the key do double duty. This really seems comparable to the current approach in terms of API complexity, so I'll update the API; bring back this version.
const String alignedItem = 'alignedItem';
SliverCoordinator(
callback: (ScrollNotification notifcation, SliverCoordinatorData data) {
if (notification is ScrollEndNotification && data.hasLayoutInfo(alignedItem)) {
...
}
},
child: CustomScrollView(
slivers: <Widget>[
CoordinatedSliver(
id: alignedItem, // required parameter
child: ...,
),
...
],
),
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// [CoordinatedSliver]s. It cannot be used to change sliver layouts. Typical use cases: | |
| /// [CoordinatedSliver]s. It cannot be used to change the layout of the sliver. Typical use cases: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really interesting, it might be worth expanding on this a bit more.
Slivers don't need scroll notifications, because they know everything about the scroll position and whether or not scrolling is occurring. A good example of this is the floating/snapping sliver persistent header. When scrolling stope, it triggers its own expand/collapse animation:
| void maybeStartSnapAnimation(ScrollDirection direction) { |
It actually documents there one of the scenarios this is meant to provide for:
/// If the header isn't already fully exposed, then scroll it into view.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, the scroll notifications aren't for sliver layout, they're for triggering behaviors that are a consequence of sliver layouts. I can make this clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should document this frame delay, explaining we need to wait until after layout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! We should probably check we're still mounted here. That gets us in these post frame callbacks. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
YES
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this nullable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's no longer nullable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these have getters and setters that trigger layout if they change? Or maybe in the case of the id changing, would we need a _replace or _update method on SliverCoordinatorData?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic updates to this table aren't needed. The SliverCoordinatorData's internal table which maps from ids to sliver geometry and constraints, is cleared when layout begins. It's used to lookup geometry and constraints for the most recent layout and whatever ids were in use at that time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is cleared when layout begins.
Right, but how would layout be triggered? Same with id, when updateRenderObject is called, if data or id change, this will not trigger a layout for the coordinated sliver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing a CoordinatedSliver's id or its data should not trigger a layout. When a layout does happen (for the usual reasons) the updated id and data will be visible to the CoordinatedSliver's callback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if layout ides are swapped? It won't trigger the callback until scrolling occurs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the others, this will need every permutation of vertical/horizontal - reversed/not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
…l notification (#146654) The scroll notification events reported for a press-drag-release gesture within a scrollable on a touch screen device begin with a `ScrollStartNotification`, followed by a series of `ScrollUpdateNotifications`, and conclude with a `ScrollEndNotification`. This protocol can be used to defer work until an interactive scroll gesture ends. For example, you might defer updating a scrollable's contents via network requests until the scroll has ended, or you might want to automatically auto-scroll at that time. In the example that follows the CustomScrollView automatically scrolls so that the last partially visible fixed-height item is completely visible when the scroll gesture ends. Many iOS applications do this kind of thing. It only makes sense to auto-scroll when the user isn't actively dragging the scrollable around. It's easy enough to do this by reacting to a ScrollEndNotifcation by auto-scrolling to align the last fixed-height list item ([source code](https://gist.github.com/HansMuller/13e2a7adadc9afb3803ba7848b20c410)). https://github.com/flutter/flutter/assets/1377460/a6e6fc77-6742-4f98-81ba-446536535f73 Dragging the scrollbar thumb in a desktop application is a similar user gesture. Currently it's not possible to defer work or auto-scroll (or whatever) while the scrollable is actively being dragged via the scrollbar thumb because each scrollbar thumb motion is mapped to a scroll start - scroll update - scroll end series of notifications. On a desktop platform, the same code behaves quite differently when the scrollbar thumb is dragged. https://github.com/flutter/flutter/assets/1377460/2593d8a3-639c-407f-80c1-6e6f67fb8c5f The stream of scroll-end events triggers auto-scrolling every time the thumb moves. From the user's perspective this feels like a losing struggle. One can also detect the beginning and end of a touch-drag by listening to the value of a ScrollPosition's `isScrollingNotifier`. This approach suffers from a similar problem: during a scrollbar thumb-drag, the `isScrollingNotifier` value isn't updated at all. This PR refactors the RawScrollbar implementation to effectively use a ScrollDragController to manage scrolls caused by dragging the scrollbar's thumb. Doing so means that dragging the thumb will produce the same notifications as dragging the scrollable on a touch device. Now desktop applications can choose to respond to scrollbar thumb drags in the same that they respond to drag scrolling on a touch screen. With the changes included here, the desktop or web version of the app works as expected, whether you're listing to scroll notifications or the scroll position's `isScrollingNotifier`. https://github.com/flutter/flutter/assets/1377460/67435c40-a866-4735-a19b-e3d68eac8139 This PR also makes the second [ScrollPosition API doc example](https://api.flutter.dev/flutter/widgets/ScrollPosition-class.html#cupertino.ScrollPosition.2) work as expected when used with the DartPad that's part of API doc page. Desktop applications also see scroll start-update-end notifications due to the mouse wheel. There is no touch screen analog for the mouse wheel, so an application that wanted to enable this kind of auto-scrolling alignment would have to include a heuristic that dealt with the sequence of small scrolls triggered by the mouse wheel. Here's an example of that: [source code](https://gist.github.com/HansMuller/ce5c474a458f5f4bcc07b0d621843165). This version of the app does not auto-align in response to small changes, wether they're triggered by dragging the scrollbar thumb of the mouse wheel. Related sliver utility PRs: #143538, #143196, #143325.
997da02 to
27211e9
Compare
921bac1 to
5262d62
Compare
A sliver that is pinned to the start of its `CustomScrollView` and reacts to scrolling by resizing between the intrinsic sizes of its min and max extent prototypes. The minimum and maximum sizes of this sliver are defined by `minExtentPrototype` and `maxExtentPrototype`, a pair of widgets that are laid out once. You can use `SizedBox` widgets to define the size limits. This sliver is preferable to the general purpose `SliverPersistentHeader` for its relatively narrow use case because there's no need to create a `SliverPersistentHeaderDelegate` or to predict the header's minimum or maximum size. The sample shows how this sliver's two extent prototype properties can be used to create a resizing header whose minimum and maximum sizes match small and large configurations of the same header widget. https://github.com/flutter/flutter/assets/1377460/fa7ced98-9d92-4d13-b093-50392118c213 Related sliver utility PRs: #143538, #143196, #127340.
A sliver that remains �pinned� to the top of the scroll view. Subsequent slivers scroll behind it. Typically the sliver is created as the first item in the list however it can be inserted anywhere and it will always stop at the top of the scroll view. When the scrolling axis is vertical, the PinnedHeaderSliver�s height is defined by its widget child. Multiple PinnedHeaderSlivers will layout one after the other, once they've scrolled to the top. This sliver is preferable to the general purpose SliverPersistentHeader - for its relatively narrow use case - because there's no need to create a [SliverPersistentHeaderDelegate] or to predict the header's size. Here's a [working demo in DartPad](https://dartpad.dev/?id=3b3f24c14fa201f752407a21ca9c9456). https://github.com/flutter/flutter/assets/1377460/943f2e02-8e73-48b7-90be-61168978ff71 Related sliver utility PRs: #143538, #143325, #127340.
Piinks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If SliverCoordinator functions primarily like a ScrollNotification, why not consider adding functionality in ScrollNotification or Viewport or ScrollView - to just look up slivers in the viewport by their key and check on things like geometry and constraints that way?
That way folks would not have to additionally wrap their slivers in CoordinatedSlivers.
That could make for a much simpler implementation and less surface to maintain. Folks are already accustomed to using ScrollNotification, introducing something new that does the same thing feels like more cognitive load for users.
This also feels pretty low level and advanced, expecting folks to know about SliverGeometry and SliverConstraints, so I am not sure that having the extra wrappings of classes around a ScrollNotification is needed. We'll likely use this type of functionality to build higher level widgets that will be more widely used.
What are your thoughts on this? :)
| ); | ||
| } | ||
|
|
||
| // Called each time a scroll gesture ends. If the alignedItem overlaps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Called each time a scroll gesture ends. If the alignedItem overlaps | |
| // Called each time a scroll gesture ends. If the alignedItem is only partially visible |
Is this what you mean by overlap here? Or is it to do with one sliver overlapping another?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I meant by "alignedItem overlaps either end of the CustomScrollView's viewport", yes. Just saying "partially visible" is ambiguous since there are lots of other reasons an item might be partially visible. Will weave "visible" in there just to make it clearer.
| final SliverConstraints constraints = data.getSliverConstraints(alignedItemId); | ||
| final SliverGeometry geometry = data.getSliverGeometry(alignedItemId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really requires folks to learn slivers deeply, are there common scenarios we might like to provide methods for instead as far as querying the state of a given coordinated sliver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should at least have an isVisible getter, to quickly skip doing work if it is not even visible at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we attached this info to the ScrollableState instead of a SliverCoodinator, then the SliverCoordinatorData object could be dispensed with and something like ScrollableState.of(context).hasSliverLayoutInfo(key) would obviate the public SliverCoordinatorData class. More on this below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think ScrollableState has any knowledge of what is visible. Slivers are managed by the Viewport.
| /// [SliverCoordinatorData] parameter includes the | ||
| /// [SliverConstraints] and [SliverGeometry] computed for each | ||
| /// [CoordinatedSliver]. | ||
| final SliverCoordinatorCallback callback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call this something that indicates when it is called? Like maybe onScrollNotification, instead of just callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, something like onScrolEndlNotification would be much clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is cleared when layout begins.
Right, but how would layout be triggered? Same with id, when updateRenderObject is called, if data or id change, this will not trigger a layout for the coordinated sliver.
| } | ||
|
|
||
| void autoScrollTo(double offset) { | ||
| scrollController.position.animateTo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| scrollController.position.animateTo( | |
| scrollController.animateTo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, done.
I will look into this. It might be possible to squirrel away the sliver geometry and constraints - for slivers with a key - in ScrollableState. Unfortunately, it's not safe to do things like auto-scroll from a scroll notification listener. However, if we believe this is only a low-level mechanism, we could just document the fact that the notification listener must That would make the example look something like this. Definitely more boilerplate, but no new classes: void maybeAutoScrollAlignedItem(ScrollableState scrollable) {
final SliverConstraints constraints = scrollable.getSliverConstraints(alignedItemId);
final SliverGeometry geometry = scrollable.getSliverGeometry(alignedItemId);
final double scrollOffset = constraints.scrollOffset;
final double overflow = geometry.maxPaintExtent - geometry.paintExtent;
if (overflow > 0 && overflow < geometry.scrollExtent) { // indicates partial visibility
if (scrollOffset > 0) {
autoScrollTo(constraints.precedingScrollExtent); // top
} else if (scrollOffset == 0) {
autoScrollTo(scrollController.position.pixels + overflow); // bottom
}
}
}
// This method is boilerplate that's not present in the current API. I suppose it
// could be provided as a static utility method on ScrollEndNotification, to
// avoid requiring developers to copy this. Like:
// ScrollEndNotification.callScrollableStateCallback(notification, mabeAutoScrollAlignedItem)
bool handleScrollEndNotification(ScrollEndNotification notification) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
if (context.mounted) {
ScrollableState? scrollable = Scrollable.maybeOf(context);
if (scrollable != null && scrollable.isSliverVisible(alignedItemId)) {
maybeAutoScrollAlignedItems(scrollableState);
}
}
});
return true;
}
NotificationListener<ScrollEndNotification>(
onNotification: handleScrollEndNotification,
child: CustomScrollView( ...)
)
Right, this is intended to be used to build Sliver-level utilities that are relatively high level. |
I don't know that these need to be squirreled away. :) Every render sliver has constraints and a geometry already available as public API. |
Good point about the squirreling. I will take a crack at building a simpler version of this API that takes advantage of the existing RenderSliver properties. |
18b1661 to
e5e5e96
Compare
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact "@test-exemption-reviewer" in the #hackers channel in Chat (don't just cc them here, they won't see it! Use Discord!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
…erCoordinatorData
…tification example.
e69e7d2 to
edf11a9
Compare
Piinks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…ver constraints and geometry (flutter/flutter#143538)
* master: (88 commits) Fix scheduler event loop being stuck due to task with Priority.idle (flutter#151168) Fix result propagation in RenderSliverEdgeInsetsPadding.hitTestChildren (flutter#149825) docImports for flutter_test (flutter#151189) Interactable ScrollView content when settling a scroll activity (flutter#145848) [flutter_tools] Update the mapping for the Dart SDK internal URI (flutter#151170) Roll pub packages (flutter#151129) Fix typo (flutter#151192) [tool] Fix `stdin.flush` calls on processes started by `FakeProcessManager` (flutter#151183) Roll Flutter Engine from 433d360eee11 to 44278941443e (4 revisions) (flutter#151186) Use `ErrorHandlingFileSystem.deleteIfExists` when deleting .plugin_symlinks (flutter#151073) ScrollEndNotification example: auto-scroll based on RenderSliver constraints and geometry (flutter#143538) Roll Packages from 412ec46 to d2705fb (13 revisions) (flutter#151169) docimports for painting (flutter#151143) docimports for scheduler (flutter#151126) `dismissible.dart` code cleanup (flutter#150276) docimports for physics (flutter#151125) docimports for services (flutter#151134) docimports for cupertino (flutter#151149) docimports for gestures (flutter#151123) Docimports for foundation (flutter#151119) ...
flutter/flutter@99bb2ff...af913a7 2024-07-02 [email protected] Use `ErrorHandlingFileSystem.deleteIfExists` when deleting .plugin_symlinks (flutter/flutter#151073) 2024-07-02 [email protected] ScrollEndNotification example: auto-scroll based on RenderSliver constraints and geometry (flutter/flutter#143538) 2024-07-02 [email protected] Roll Packages from 412ec46 to d2705fb (13 revisions) (flutter/flutter#151169) 2024-07-02 [email protected] docimports for painting (flutter/flutter#151143) 2024-07-02 [email protected] docimports for scheduler (flutter/flutter#151126) 2024-07-02 [email protected] `dismissible.dart` code cleanup (flutter/flutter#150276) 2024-07-02 [email protected] docimports for physics (flutter/flutter#151125) 2024-07-02 [email protected] docimports for services (flutter/flutter#151134) 2024-07-02 [email protected] docimports for cupertino (flutter/flutter#151149) 2024-07-02 [email protected] docimports for gestures (flutter/flutter#151123) 2024-07-02 [email protected] Docimports for foundation (flutter/flutter#151119) 2024-07-02 [email protected] docimports for semantics (flutter/flutter#151132) 2024-07-02 [email protected] [flutter_driver] add allocator mtl to memory event allowlist. (flutter/flutter#151153) 2024-07-02 [email protected] Roll Flutter Engine from 40c087b31515 to 433d360eee11 (7 revisions) (flutter/flutter#151165) 2024-07-02 [email protected] Refactor BuildInfo to always require packageConfigPath (flutter/flutter#150559) 2024-07-02 [email protected] Roll Flutter Engine from d3c5bd66a78f to 40c087b31515 (1 revision) (flutter/flutter#151156) 2024-07-02 [email protected] Roll Flutter Engine from fc5bc14e6091 to d3c5bd66a78f (1 revision) (flutter/flutter#151155) 2024-07-02 [email protected] Fix: `CupertinoActionSheet` should take up max height when actions section is short (flutter/flutter#150708) 2024-07-02 [email protected] Roll Flutter Engine from 3456fee1a6b9 to fc5bc14e6091 (8 revisions) (flutter/flutter#151150) 2024-07-02 [email protected] [tool] remove some temporary printTrace calls (flutter/flutter#151074) 2024-07-01 [email protected] Implementing a few switch statements (flutter/flutter#150946) 2024-07-01 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Upgrade template Gradle, App AGP, Module AGP, and Kotlin versions, and tests (#150969)" (flutter/flutter#151147) 2024-07-01 [email protected] Upgrade template Gradle, App AGP, Module AGP, and Kotlin versions, and tests (flutter/flutter#150969) 2024-07-01 [email protected] Roll Flutter Engine from b57a044ed10f to 3456fee1a6b9 (5 revisions) (flutter/flutter#151127) 2024-07-01 [email protected] Read AndroidManifest.xml and emit manifest-aar-impeller-(enabled|disabled) analytics (flutter/flutter#150970) 2024-07-01 [email protected] More docimports for animation library (flutter/flutter#151011) 2024-07-01 [email protected] Bump dartdoc to 8.0.10 (flutter/flutter#151107) 2024-07-01 [email protected] Fix missing `[` in docs (flutter/flutter#151091) 2024-07-01 [email protected] Roll pub packages (flutter/flutter#151028) 2024-07-01 [email protected] Fix teardown of a FocusScopeNode in material/app_test (flutter/flutter#151115) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…traints and geometry (flutter#143538) Adds a new ScrollNotificationEnd example that demonstrates how to trigger an auto-scroll based on an individual sliver's `SliverConstraints` and `SliverGeometry`. Then new example auto-scrolls one special "aligned item" sliver to the top or bottom of the viewport, whenever it's partially visible (because it overlaps the top or bottom of the viewport). This example differs from the existing ScrollEndNotification example because the layout of the to-be aligned sliver is retrieved from its `RenderSliver` via a GlobalKey. The new example does not rely on all of the list items having the same extent.
…ver constraints and geometry (flutter/flutter#143538)

Adds a new ScrollNotificationEnd example that demonstrates how to trigger an auto-scroll based on an individual sliver's
SliverConstraintsandSliverGeometry.Then new example auto-scrolls one special "aligned item" sliver to the top or bottom of the viewport, whenever it's partially visible (because it overlaps the top or bottom of the viewport). This example differs from the existing ScrollEndNotification example because the layout of the to-be aligned sliver is retrieved from its
RenderSlivervia aGlobalKey. The new example does not rely on all of the list items having the same extent.