From e92f7cd8fe3affadf714bca28c8b966cb5b73415 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Fri, 3 Sep 2021 16:29:43 -0500 Subject: [PATCH] Update StretchingOverscrollIndicator for reversed scrollables (#89242) * Update overscroll indicator for reverse * Review feedback * Review feedback --- .../lib/src/widgets/overscroll_indicator.dart | 33 +++++-- .../overscroll_stretch_indicator_test.dart | 91 ++++++++++++++++++- 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index 3796963a2a4..2f893681c38 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -708,6 +708,28 @@ class _StretchingOverscrollIndicatorState extends State 0 + ? AlignmentDirectional.topCenter + : AlignmentDirectional.bottomCenter; + case AxisDirection.right: + return overscroll > 0 + ? AlignmentDirectional.centerEnd + : AlignmentDirectional.centerStart; + case AxisDirection.down: + return overscroll > 0 + ? AlignmentDirectional.bottomCenter + : AlignmentDirectional.topCenter; + case AxisDirection.left: + return overscroll > 0 + ? AlignmentDirectional.centerStart + : AlignmentDirectional.centerEnd; + } + } + @override void dispose() { _stretchController.dispose(); @@ -724,23 +746,20 @@ class _StretchingOverscrollIndicatorState extends State 0 - ? AlignmentDirectional.centerEnd - : AlignmentDirectional.centerStart; break; case Axis.vertical: y += stretch; - alignment = (_lastOverscrollNotification?.overscroll ?? 0) > 0 - ? AlignmentDirectional.bottomCenter - : AlignmentDirectional.topCenter; break; } + final AlignmentDirectional alignment = _getAlignmentForAxisDirection( + _lastOverscrollNotification?.overscroll ?? 0.0 + ); + return Transform( alignment: alignment, transform: Matrix4.diagonal3Values(x, y, 1.0), diff --git a/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart b/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart index cd7504435e0..f5bed56550b 100644 --- a/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart +++ b/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart @@ -16,16 +16,28 @@ void main() { Key box2Key, Key box3Key, ScrollController controller, { - Axis? axis, + Axis axis = Axis.vertical, + bool reverse = false, }) { + final AxisDirection axisDirection; + switch (axis) { + case Axis.horizontal: + axisDirection = reverse ? AxisDirection.left : AxisDirection.right; + break; + case Axis.vertical: + axisDirection = reverse ? AxisDirection.up : AxisDirection.down; + break; + } + return Directionality( textDirection: TextDirection.ltr, child: ScrollConfiguration( behavior: const ScrollBehavior().copyWith(overscroll: false), child: StretchingOverscrollIndicator( - axisDirection: axis == null ? AxisDirection.down : AxisDirection.right, + axisDirection: axisDirection, child: CustomScrollView( - scrollDirection: axis ?? Axis.vertical, + reverse: reverse, + scrollDirection: axis, controller: controller, slivers: [ SliverToBoxAdapter(child: Container( @@ -118,6 +130,79 @@ void main() { ); }); + testWidgets('Stretch overscroll works in reverse - vertical', (WidgetTester tester) async { + final Key box1Key = UniqueKey(); + final Key box2Key = UniqueKey(); + final Key box3Key = UniqueKey(); + final ScrollController controller = ScrollController(); + await tester.pumpWidget( + buildTest(box1Key, box2Key, box3Key, controller, reverse: true), + ); + + expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); + expect(find.byType(GlowingOverscrollIndicator), findsNothing); + final RenderBox box1 = tester.renderObject(find.byKey(box1Key)); + final RenderBox box2 = tester.renderObject(find.byKey(box2Key)); + final RenderBox box3 = tester.renderObject(find.byKey(box3Key)); + + expect(controller.offset, 0.0); + expect(box1.localToGlobal(Offset.zero), const Offset(0.0, 350.0)); + expect(box2.localToGlobal(Offset.zero), const Offset(0.0, 100.0)); + expect(box3.localToGlobal(Offset.zero), const Offset(0.0, -150.0)); + + final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CustomScrollView))); + // Overscroll + await gesture.moveBy(const Offset(0.0, -200.0)); + await tester.pumpAndSettle(); + expect(box1.localToGlobal(Offset.zero).dy, lessThan(350.0)); + expect(box2.localToGlobal(Offset.zero).dy, lessThan(100.0)); + expect(box3.localToGlobal(Offset.zero).dy, lessThan(-150.0)); + await expectLater( + find.byType(CustomScrollView), + matchesGoldenFile('overscroll_stretch.vertical.reverse.png'), + ); + }); + + testWidgets('Stretch overscroll horizontally', (WidgetTester tester) async { + final Key box1Key = UniqueKey(); + final Key box2Key = UniqueKey(); + final Key box3Key = UniqueKey(); + final ScrollController controller = ScrollController(); + await tester.pumpWidget( + buildTest( + box1Key, + box2Key, + box3Key, + controller, + axis: Axis.horizontal, + reverse: true, + ), + ); + + expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); + expect(find.byType(GlowingOverscrollIndicator), findsNothing); + final RenderBox box1 = tester.renderObject(find.byKey(box1Key)); + final RenderBox box2 = tester.renderObject(find.byKey(box2Key)); + final RenderBox box3 = tester.renderObject(find.byKey(box3Key)); + + expect(controller.offset, 0.0); + expect(box1.localToGlobal(Offset.zero), const Offset(500.0, 0.0)); + expect(box2.localToGlobal(Offset.zero), const Offset(200.0, 0.0)); + expect(box3.localToGlobal(Offset.zero), const Offset(-100.0, 0.0)); + + final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CustomScrollView))); + // Overscroll + await gesture.moveBy(const Offset(200.0, 0.0)); + await tester.pumpAndSettle(); + expect(box1.localToGlobal(Offset.zero).dx, greaterThan(500.0)); + expect(box2.localToGlobal(Offset.zero).dx, greaterThan(200.0)); + expect(box3.localToGlobal(Offset.zero).dx, greaterThan(-100.0)); + await expectLater( + find.byType(CustomScrollView), + matchesGoldenFile('overscroll_stretch.horizontal.reverse.png'), + ); + }); + testWidgets('Stretch overscroll horizontally', (WidgetTester tester) async { final Key box1Key = UniqueKey(); final Key box2Key = UniqueKey();