diff --git a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart index e29ba367cd..42610843df 100644 --- a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart @@ -248,13 +248,16 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda to: trailingScrollOffset, ); + final double targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; + final int targetLastIndexForPaint = targetEndScrollOffsetForPaint.isFinite ? + getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint, itemExtent) : null; geometry = new SliverGeometry( scrollExtent: estimatedMaxScrollOffset, paintExtent: paintExtent, cacheExtent: cacheExtent, maxPaintExtent: estimatedMaxScrollOffset, // Conservative to avoid flickering away the clip during scroll. - hasVisualOverflow: (targetLastIndex != null && lastIndex >= targetLastIndex) + hasVisualOverflow: (targetLastIndexForPaint != null && lastIndex >= targetLastIndexForPaint) || constraints.scrollOffset > 0.0, ); diff --git a/packages/flutter/lib/src/rendering/sliver_list.dart b/packages/flutter/lib/src/rendering/sliver_list.dart index 2fd6569935..41849fbace 100644 --- a/packages/flutter/lib/src/rendering/sliver_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_list.dart @@ -274,13 +274,14 @@ class RenderSliverList extends RenderSliverMultiBoxAdaptor { from: childScrollOffset(firstChild), to: endScrollOffset, ); + final double targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; geometry = new SliverGeometry( scrollExtent: estimatedMaxScrollOffset, paintExtent: paintExtent, cacheExtent: cacheExtent, maxPaintExtent: estimatedMaxScrollOffset, // Conservative to avoid flickering away the clip during scroll. - hasVisualOverflow: endScrollOffset > targetEndScrollOffset || constraints.scrollOffset > 0.0, + hasVisualOverflow: endScrollOffset > targetEndScrollOffsetForPaint || constraints.scrollOffset > 0.0, ); // We may have started the layout while scrolled to the end, which would not diff --git a/packages/flutter/test/widgets/list_view_test.dart b/packages/flutter/test/widgets/list_view_test.dart index 4fbb4837ee..1d0bea2690 100644 --- a/packages/flutter/test/widgets/list_view_test.dart +++ b/packages/flutter/test/widgets/list_view_test.dart @@ -5,6 +5,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/widgets.dart'; +import '../rendering/mock_canvas.dart'; + class TestSliverChildListDelegate extends SliverChildListDelegate { TestSliverChildListDelegate(List children) : super(children); @@ -293,4 +295,114 @@ void main() { // Leave left/right padding as is for children. expect(innerMediaQueryPadding, const EdgeInsets.symmetric(horizontal: 30.0)); }); + + testWidgets('ListView clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/17426. + + await tester.pumpWidget( + new Directionality( + textDirection: TextDirection.ltr, + child: new Center( + child: new Container( + height: 200.0, + child: new ListView( + cacheExtent: 500.0, + children: [ + new Container( + height: 90.0, + ), + new Container( + height: 110.0, + ), + new Container( + height: 80.0, + ), + ], + ), + ), + ), + ), + ); + + expect(find.byType(Viewport), paints..clipRect()); + }); + + testWidgets('ListView does not clips if no overflow', (WidgetTester tester) async { + await tester.pumpWidget( + new Directionality( + textDirection: TextDirection.ltr, + child: new Center( + child: new Container( + height: 200.0, + child: new ListView( + cacheExtent: 500.0, + children: [ + new Container( + height: 100.0, + ), + ], + ), + ), + ), + ), + ); + + expect(find.byType(Viewport), isNot(paints..clipRect())); + }); + + testWidgets('ListView (fixed extent) clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/17426. + + await tester.pumpWidget( + new Directionality( + textDirection: TextDirection.ltr, + child: new Center( + child: new Container( + height: 200.0, + child: new ListView( + itemExtent: 100.0, + cacheExtent: 500.0, + children: [ + new Container( + height: 100.0, + ), + new Container( + height: 100.0, + ), + new Container( + height: 100.0, + ), + ], + ), + ), + ), + ), + ); + + expect(find.byType(Viewport), paints..clipRect()); + }); + + testWidgets('ListView (fixed extent) does not clips if no overflow', (WidgetTester tester) async { + await tester.pumpWidget( + new Directionality( + textDirection: TextDirection.ltr, + child: new Center( + child: new Container( + height: 200.0, + child: new ListView( + itemExtent: 100.0, + cacheExtent: 500.0, + children: [ + new Container( + height: 100.0, + ), + ], + ), + ), + ), + ), + ); + + expect(find.byType(Viewport), isNot(paints..clipRect())); + }); }