diff --git a/packages/flutter/lib/src/rendering/sliver_group.dart b/packages/flutter/lib/src/rendering/sliver_group.dart index 40e8ee85ec7bf..e336602dfb1f5 100644 --- a/packages/flutter/lib/src/rendering/sliver_group.dart +++ b/packages/flutter/lib/src/rendering/sliver_group.dart @@ -284,9 +284,21 @@ class RenderSliverMainAxisGroup extends RenderSliver with ContainerRenderObjectM offset += child.geometry!.scrollExtent; child = childAfter(child); } + + final double paintExtent = calculatePaintOffset( + constraints, + from: math.min(constraints.scrollOffset, 0), + to: totalScrollExtent, + ); + final double cacheExtent = calculateCacheOffset( + constraints, + from: math.min(constraints.scrollOffset, 0), + to: totalScrollExtent, + ); geometry = SliverGeometry( scrollExtent: totalScrollExtent, - paintExtent: calculatePaintOffset(constraints, from: 0, to: totalScrollExtent), + paintExtent: paintExtent, + cacheExtent: cacheExtent, maxPaintExtent: maxPaintExtent, hasVisualOverflow: totalScrollExtent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0, ); diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index b0cf025e260e1..49cabeae38d7b 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -692,6 +692,42 @@ void main() { expect(controller.offset, 1000); expect(counter, equals(2)); }); + + testWidgets('SliverMainAxisGroup does not cause extra builds for lazy sliver children', (WidgetTester tester) async { + // By setting the correct SliverGeometry in the first SliverMainAxisGroup, + // the following SliverMainAxisGroups will not perform extra work. + final Map buildsPerGroup = { + 0 : 0, + 1 : 0, + 2 : 0, + }; + await tester.pumpWidget(MaterialApp( + home: CustomScrollView( + slivers: [ + for (int groupIndex = 0; groupIndex < 3; groupIndex++) + SliverMainAxisGroup( + slivers: [ + SliverList.builder( + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + buildsPerGroup[groupIndex] = buildsPerGroup[groupIndex]! + 1; + return const SizedBox.square(dimension: 50); + }, + ), + ], + ), + ] + ), + )); + await tester.pumpAndSettle(); + expect(buildsPerGroup[0], 17); // First sliver filled the screen and cache extent + expect(buildsPerGroup[1], 1); // Second only lays out one child + expect(buildsPerGroup[2], 1); // Third only lays out one child + final RenderSliverMainAxisGroup renderGroup = tester.renderObject( + find.byType(SliverMainAxisGroup).first, + ) as RenderSliverMainAxisGroup; + expect(renderGroup.geometry!.cacheExtent, 850.0); + }); } Widget _buildSliverList({