diff --git a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart index 2273acc134..1323440b67 100644 --- a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart +++ b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart @@ -524,7 +524,13 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver ); if (addExtent) childOffset += mainAxisUnit * paintExtentOf(child); - context.paintChild(child, childOffset); + + // If the child's visible interval (mainAxisLowerBound, mainAxisLowerBound + paintExtentOf(child)) + // does not intersect the paint extent interval (0, constraints.remainingPaintExtent), it's hidden. + final double mainAxisLowerBound = mainAxisDelta + (addExtent ? paintExtentOf(child) : 0); + if (mainAxisLowerBound < constraints.remainingPaintExtent && mainAxisLowerBound + paintExtentOf(child) > 0) + context.paintChild(child, childOffset); + child = childAfter(child); } } diff --git a/packages/flutter/test/widgets/keep_alive_test.dart b/packages/flutter/test/widgets/keep_alive_test.dart index 566fa0e855..05e3bafd97 100644 --- a/packages/flutter/test/widgets/keep_alive_test.dart +++ b/packages/flutter/test/widgets/keep_alive_test.dart @@ -307,14 +307,14 @@ void main() { ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' ' │\n' - ' └─child with index 2: RenderLimitedBox#00000\n' + ' └─child with index 2: RenderLimitedBox#00000 NEEDS-PAINT\n' ' │ parentData: index=2; layoutOffset=800.0\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' ' │ maxWidth: 400.0\n' ' │ maxHeight: 400.0\n' ' │\n' - ' └─child: RenderCustomPaint#00000\n' + ' └─child: RenderCustomPaint#00000 NEEDS-PAINT\n' ' parentData: (can use size)\n' ' constraints: BoxConstraints(w=800.0, h=400.0)\n' ' size: Size(800.0, 400.0)\n' @@ -412,14 +412,14 @@ void main() { ' │ cacheExtent: 1100.0)\n' ' │ currently live children: 4 to 7\n' ' │\n' - ' ├─child with index 4: RenderLimitedBox#00000\n' + ' ├─child with index 4: RenderLimitedBox#00000 NEEDS-PAINT\n' ' │ │ parentData: index=4; layoutOffset=1600.0\n' ' │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ │ size: Size(800.0, 400.0)\n' ' │ │ maxWidth: 400.0\n' ' │ │ maxHeight: 400.0\n' ' │ │\n' - ' │ └─child: RenderCustomPaint#00000\n' + ' │ └─child: RenderCustomPaint#00000 NEEDS-PAINT\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' @@ -448,14 +448,14 @@ void main() { ' │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' │ size: Size(800.0, 400.0)\n' ' │\n' - ' ├─child with index 7: RenderLimitedBox#00000\n' + ' ├─child with index 7: RenderLimitedBox#00000 NEEDS-PAINT\n' ' ╎ │ parentData: index=7; layoutOffset=2800.0\n' ' ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' ╎ │ size: Size(800.0, 400.0)\n' ' ╎ │ maxWidth: 400.0\n' ' ╎ │ maxHeight: 400.0\n' ' ╎ │\n' - ' ╎ └─child: RenderCustomPaint#00000\n' + ' ╎ └─child: RenderCustomPaint#00000 NEEDS-PAINT\n' ' ╎ parentData: (can use size)\n' ' ╎ constraints: BoxConstraints(w=800.0, h=400.0)\n' ' ╎ size: Size(800.0, 400.0)\n' diff --git a/packages/flutter/test/widgets/list_view_viewporting_test.dart b/packages/flutter/test/widgets/list_view_viewporting_test.dart index c4b8632c2d..9e4fb457c3 100644 --- a/packages/flutter/test/widgets/list_view_viewporting_test.dart +++ b/packages/flutter/test/widgets/list_view_viewporting_test.dart @@ -459,5 +459,36 @@ void main() { final RenderSliverList list = tester.renderObject(find.byType(SliverList)); expect(list, paintsExactlyCountTimes(#drawParagraph, 2)); - }, skip: true); + }); + + testWidgets('ListView should paint with offset', (WidgetTester tester) async { + await tester.pumpWidget( + new MaterialApp( + home: new Scaffold( + body: new Container( + height: 500.0, + child: new CustomScrollView( + controller: new ScrollController(initialScrollOffset: 120.0), + slivers: [ + const SliverAppBar( + expandedHeight: 250.0, + ), + new SliverList( + delegate: new ListView.builder( + itemExtent: 100.0, + itemCount: 100, + itemBuilder: (_, __) => new Container( + height: 40.0, + child: const Text('hey'), + )).childrenDelegate), + ], + ) + ) + ) + ) + ); + + final RenderObject renderObject = tester.renderObject(find.byType(Scrollable)); + expect(renderObject, paintsExactlyCountTimes(#drawParagraph, 10)); + }); } diff --git a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart index 3ba4b77ee0..d6177f6436 100644 --- a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart +++ b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart @@ -82,7 +82,7 @@ void main() { ' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ │ layer: OffsetLayer#00000\n' ' │ │ size: Size(800.0, 600.0)\n' - ' │ │ metrics: 75.0% useful (1 bad vs 3 good)\n' + ' │ │ metrics: 66.7% useful (1 bad vs 2 good)\n' ' │ │ diagnosis: insufficient data to draw conclusion (less than five\n' ' │ │ repaints)\n' ' │ │\n' @@ -103,9 +103,9 @@ void main() { ' └─child with index 1: RenderRepaintBoundary#00000\n' ' │ parentData: index=1; layoutOffset=600.0\n' ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' - ' │ layer: OffsetLayer#00000\n' + ' │ layer: OffsetLayer#00000 DETACHED\n' ' │ size: Size(800.0, 600.0)\n' - ' │ metrics: 75.0% useful (1 bad vs 3 good)\n' + ' │ metrics: 50.0% useful (1 bad vs 1 good)\n' ' │ diagnosis: insufficient data to draw conclusion (less than five\n' ' │ repaints)\n' ' │\n'