Fix the issue with SliverMainAxisGroups growing in the reverse direction during layout. (#171005)

Fixes: #170991

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
yim 2025-07-10 08:55:05 +08:00 committed by GitHub
parent 01f7007a3f
commit 3ed1ca72e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 5 deletions

View File

@ -263,7 +263,14 @@ class RenderSliverMainAxisGroup extends RenderSliver
double maxPaintExtent = 0;
double paintOffset = constraints.overlap;
RenderSliver? child = firstChild;
final (
RenderSliver? leadingChild,
RenderSliver? Function(RenderSliver child) advance,
) = switch (constraints.growthDirection) {
GrowthDirection.forward => (firstChild, childAfter),
GrowthDirection.reverse => (lastChild, childBefore),
};
RenderSliver? child = leadingChild;
while (child != null) {
final double beforeOffsetPaintExtent = calculatePaintOffset(
constraints,
@ -298,7 +305,7 @@ class RenderSliverMainAxisGroup extends RenderSliver
layoutOffset += childLayoutGeometry.layoutExtent;
maxPaintExtent += childLayoutGeometry.maxPaintExtent;
paintOffset = math.max(childPaintOffset + childLayoutGeometry.paintExtent, paintOffset);
child = childAfter(child);
child = advance(child);
assert(() {
if (child != null && maxPaintExtent.isInfinite) {
throw FlutterError(
@ -349,11 +356,14 @@ class RenderSliverMainAxisGroup extends RenderSliver
// Update the children's paintOffset based on the direction again, which
// must be done after obtaining the `paintExtent`.
child = firstChild;
child = leadingChild;
while (child != null) {
final SliverPhysicalParentData childParentData =
child.parentData! as SliverPhysicalParentData;
childParentData.paintOffset = switch (constraints.axisDirection) {
childParentData.paintOffset = switch (applyGrowthDirectionToAxisDirection(
constraints.axisDirection,
constraints.growthDirection,
)) {
AxisDirection.up => Offset(
0.0,
paintExtent - childParentData.paintOffset.dy - child.geometry!.paintExtent,
@ -364,7 +374,7 @@ class RenderSliverMainAxisGroup extends RenderSliver
),
AxisDirection.right || AxisDirection.down => childParentData.paintOffset,
};
child = childAfter(child);
child = advance(child);
}
}

View File

@ -1062,6 +1062,41 @@ void main() {
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
});
testWidgets('SliverMainAxisGroup with center', (WidgetTester tester) async {
final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
const Key centerKey = Key('center');
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(
center: centerKey,
controller: controller,
slivers: const <Widget>[
SliverMainAxisGroup(
slivers: <Widget>[
SliverToBoxAdapter(child: SizedBox(height: 50, child: Text('-2'))),
SliverToBoxAdapter(child: SizedBox(height: 50, child: Text('-1'))),
],
),
SliverMainAxisGroup(
key: centerKey,
slivers: <Widget>[
SliverToBoxAdapter(child: SizedBox(height: 50, child: Text('1'))),
SliverToBoxAdapter(child: SizedBox(height: 50, child: Text('2'))),
],
),
],
),
),
);
controller.jumpTo(-51);
await tester.pumpAndSettle();
expect(tester.getTopLeft(find.text('-1')), const Offset(0, 1));
expect(tester.getTopLeft(find.text('1')), const Offset(0, 51));
expect(tester.getTopLeft(find.text('2')), const Offset(0, 101));
expect(tester.getTopLeft(find.text('-2')), const Offset(0, -49));
});
}
Widget _buildSliverList({