Fix scroll jump when NestedScrollPosition is inertia-cancelled. (#116689)

* Fix scroll jump when NestedScrollPosition is inertia-cancelled.

* Switch to using pointerScroll(0)
This commit is contained in:
Callum Moffat 2022-12-12 19:20:30 -05:00 committed by GitHub
parent 6432fd1b15
commit 97df2b3191
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 3 deletions

View file

@ -903,7 +903,10 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
// 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);
if (delta == 0.0) {
goBallistic(0.0);
return;
}
goIdle();
updateUserScrollDirection(

View file

@ -212,7 +212,10 @@ class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollAc
// 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);
if (delta == 0.0) {
goBallistic(0.0);
return;
}
final double targetPixels =
math.min(math.max(pixels + delta, minScrollExtent), maxScrollExtent);

View file

@ -780,7 +780,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
GestureBinding.instance.pointerSignalResolver.register(event, _handlePointerScroll);
}
} else if (event is PointerScrollInertiaCancelEvent) {
position.jumpTo(position.pixels);
position.pointerScroll(0);
// Don't use the pointer signal resolver, all hit-tested scrollables should stop.
}
}

View file

@ -1012,6 +1012,54 @@ void main() {
);
});
testWidgets('Inertia-cancel event does not modify either position.', (WidgetTester tester) async {
final GlobalKey<NestedScrollViewState> globalKey = GlobalKey();
await tester.pumpWidget(buildTest(
key: globalKey,
expanded: false,
));
double appBarHeight = tester.renderObject<RenderBox>(find.byType(AppBar)).size.height;
expect(appBarHeight, 104.0);
final double scrollExtent = appBarHeight + 50.0;
expect(globalKey.currentState!.outerController.offset, 0.0);
expect(globalKey.currentState!.innerController.offset, 0.0);
// The scroll gesture should occur in the inner body, so the whole
// scroll view is scrolled.
final TestGesture gesture = await tester.startGesture(Offset(
0.0,
appBarHeight + 1.0,
));
await gesture.moveBy(Offset(0.0, -scrollExtent));
await tester.pump();
appBarHeight = tester.renderObject<RenderBox>(find.byType(AppBar)).size.height;
// This is not an expanded AppBar.
expect(appBarHeight, 104.0);
// The outer scroll controller should show an offset of the applied
// scrollExtent.
expect(globalKey.currentState!.outerController.offset, appBarHeight);
// the inner scroll controller should have scrolled equivalent to the
// difference between the applied scrollExtent and the outer extent.
expect(
globalKey.currentState!.innerController.offset,
scrollExtent - appBarHeight,
);
final TestPointer testPointer = TestPointer(3, ui.PointerDeviceKind.trackpad);
await tester.sendEventToBinding(testPointer.addPointer(
location: Offset(0.0, appBarHeight + 1.0)
));
await tester.sendEventToBinding(testPointer.scrollInertiaCancel());
// ensure no change.
expect(globalKey.currentState!.outerController.offset, appBarHeight);
expect(
globalKey.currentState!.innerController.offset,
scrollExtent - appBarHeight,
);
});
testWidgets('scrolling by less than the expanded outer extent does not scroll the inner body', (WidgetTester tester) async {
final GlobalKey<NestedScrollViewState> globalKey = GlobalKey();
await tester.pumpWidget(buildTest(key: globalKey));