Unverified Commit bfb1fc20 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Correct scroll notifications for NestedScrollView (#96482)

parent 4575a69d
......@@ -890,6 +890,9 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
}
void pointerScroll(double delta) {
// If an update is made to pointer scrolling here, consider if the same
// (or similar) change should be made in
// ScrollPositionWithSingleContext.pointerScroll.
assert(delta != 0.0);
goIdle();
......@@ -897,12 +900,15 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
delta < 0.0 ? ScrollDirection.forward : ScrollDirection.reverse,
);
// Set the isScrollingNotifier. Even if only one position actually receives
// Handle notifications. Even if only one position actually receives
// the delta, the NestedScrollView's intention is to treat multiple
// ScrollPositions as one.
_outerPosition!.isScrollingNotifier.value = true;
for (final _NestedScrollPosition position in _innerPositions)
_outerPosition!.didStartScroll();
for (final _NestedScrollPosition position in _innerPositions) {
position.isScrollingNotifier.value = true;
position.didStartScroll();
}
if (_innerPositions.isEmpty) {
// Does not enter overscroll.
......@@ -950,6 +956,11 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
_outerPosition!.applyClampedPointerSignalUpdate(outerDelta);
}
}
_outerPosition!.didEndScroll();
for (final _NestedScrollPosition position in _innerPositions) {
position.didEndScroll();
}
goBallistic(0.0);
}
......
......@@ -205,6 +205,9 @@ class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollAc
@override
void pointerScroll(double delta) {
// If an update is made to pointer scrolling here, consider if the same
// (or similar) change should be made in
// _NestedScrollCoordinator.pointerScroll.
assert(delta != 0.0);
final double targetPixels =
......
......@@ -2491,6 +2491,68 @@ void main() {
await tester.fling(find.text('Item 25'), const Offset(0.0, -50.0), 4000.0);
await tester.pumpAndSettle();
});
testWidgets('NestedScrollViewCoordinator.pointerScroll dispatches correct scroll notifications', (WidgetTester tester) async {
int scrollEnded = 0;
int scrollStarted = 0;
bool isScrolled = false;
await tester.pumpWidget(MaterialApp(
home: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification is ScrollStartNotification) {
scrollStarted += 1;
} else if (notification is ScrollEndNotification) {
scrollEnded += 1;
}
return false;
},
child: Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
isScrolled = innerBoxIsScrolled;
return <Widget>[
const SliverAppBar(
expandedHeight: 250.0,
),
];
},
body: CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: SliverFixedExtentList(
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
childCount: 30,
),
),
),
],
),
),
),
),
));
final Offset scrollEventLocation = tester.getCenter(find.byType(NestedScrollView));
final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse);
// Create a hover event so that |testPointer| has a location when generating the scroll.
testPointer.hover(scrollEventLocation);
await tester.sendEventToBinding(testPointer.scroll(const Offset(0.0, 300.0)));
await tester.pumpAndSettle();
expect(isScrolled, isTrue);
// There should have been a notification for each nested position (2).
expect(scrollStarted, 2);
expect(scrollEnded, 2);
});
}
class TestHeader extends SliverPersistentHeaderDelegate {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment