Update StretchingOverscrollIndicator for reversed scrollables (#89242)
* Update overscroll indicator for reverse
* Review feedback
* Review feedback
diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart
index 3796963..2f893681 100644
--- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart
+++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart
@@ -708,6 +708,28 @@
return false;
}
+ AlignmentDirectional _getAlignmentForAxisDirection(double overscroll) {
+ // Accounts for reversed scrollables by checking the AxisDirection
+ switch (widget.axisDirection) {
+ case AxisDirection.up:
+ return overscroll > 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 @@
final double stretch = _stretchController.value;
double x = 1.0;
double y = 1.0;
- final AlignmentDirectional alignment;
switch (widget.axis) {
case Axis.horizontal:
x += stretch;
- alignment = (_lastOverscrollNotification?.overscroll ?? 0) > 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 cd75044..f5bed56 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 @@
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: <Widget>[
SliverToBoxAdapter(child: Container(
@@ -118,6 +130,79 @@
);
});
+ 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();