Fix overflow edge case in overscrolled RenderShrinkWrappingViewport (#90419)
diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart
index 3e32b4a..9da485d 100644
--- a/packages/flutter/lib/src/rendering/viewport.dart
+++ b/packages/flutter/lib/src/rendering/viewport.dart
@@ -1933,7 +1933,7 @@
scrollOffset: math.max(0.0, correctedOffset),
overlap: math.min(0.0, correctedOffset),
layoutOffset: math.max(0.0, -correctedOffset),
- remainingPaintExtent: mainAxisExtent,
+ remainingPaintExtent: mainAxisExtent + math.min(0.0, correctedOffset),
mainAxisExtent: mainAxisExtent,
crossAxisExtent: crossAxisExtent,
growthDirection: GrowthDirection.forward,
diff --git a/packages/flutter/test/rendering/viewport_test.dart b/packages/flutter/test/rendering/viewport_test.dart
index 913eb57..2cfe466 100644
--- a/packages/flutter/test/rendering/viewport_test.dart
+++ b/packages/flutter/test/rendering/viewport_test.dart
@@ -7,6 +7,8 @@
// initialize a binding, which rendering_tester will attempt to re-initialize
// (or vice versa).
+@Tags(<String>['reduced-test-set'])
+
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
@@ -1867,6 +1869,53 @@
);
}
+ testWidgets('Constrained Shrinkwrapping viewport will not overflow on overscroll', (WidgetTester tester) async {
+ // Regression test for https://github.com/flutter/flutter/issues/89717
+ final ScrollController controller = ScrollController();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: MediaQuery(
+ data: const MediaQueryData(),
+ child: Column(
+ children: <Widget>[
+ Container(height: 100, color: const Color(0x00000000)),
+ Container(
+ height: 150,
+ color: const Color(0xFFF44336),
+ child: ListView.builder(
+ controller: controller,
+ shrinkWrap: true,
+ physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
+ itemBuilder: (BuildContext context, int index) => Text('Item $index'),
+ itemCount: 10,
+ ),
+ ),
+ Container(height: 100, color: const Color(0x00000000)),
+ ],
+ ),
+ ),
+ )
+ );
+ expect(controller.offset, 0.0);
+ expect(tester.getTopLeft(find.text('Item 0')).dy, 100.0);
+
+ // Overscroll
+ final TestGesture overscrollGesture = await tester.startGesture(tester.getCenter(find.text('Item 0')));
+ await overscrollGesture.moveBy(const Offset(0, 25));
+ await tester.pump();
+ expect(controller.offset, -25.0);
+ expect(tester.getTopLeft(find.text('Item 0')).dy, 125.0);
+ await expectLater(
+ find.byType(Directionality),
+ matchesGoldenFile('shrinkwrapped_overscroll.png'),
+ );
+ await overscrollGesture.up();
+ await tester.pumpAndSettle();
+ expect(controller.offset, 0.0);
+ expect(tester.getTopLeft(find.text('Item 0')).dy, 100.0);
+ });
+
testWidgets('Shrinkwrap allows overscrolling on default platforms - vertical', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/10949
// Scrollables should overscroll by default on iOS and macOS