Fix SliverMainAxisGroup.cacheOrigin (#175760)

Fix #175759 

The fix involves using the same logic for cache calculation on
RenderViewport.

## 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.
- [X] 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.
This commit is contained in:
manu-sncf 2025-10-21 19:04:26 +02:00 committed by GitHub
parent b5776c5e8d
commit 2e861f3527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 5 deletions

View File

@ -296,6 +296,9 @@ class RenderSliverMainAxisGroup extends RenderSliver
double paintOffset = constraints.overlap;
double maxScrollObstructionExtent = 0;
double cacheOrigin = constraints.cacheOrigin;
double remainingCacheExtent = constraints.remainingCacheExtent;
final (
RenderSliver? leadingChild,
RenderSliver? Function(RenderSliver child) advance,
@ -310,17 +313,22 @@ class RenderSliverMainAxisGroup extends RenderSliver
from: 0.0,
to: scrollOffset,
);
final double childScrollOffset = math.max(0.0, constraints.scrollOffset - scrollOffset);
final double correctedCacheOrigin = math.max(cacheOrigin, -childScrollOffset);
final double cacheExtentCorrection = cacheOrigin - correctedCacheOrigin;
child.layout(
constraints.copyWith(
scrollOffset: math.max(0.0, constraints.scrollOffset - scrollOffset),
cacheOrigin: math.min(0.0, constraints.cacheOrigin + scrollOffset),
scrollOffset: childScrollOffset,
cacheOrigin: correctedCacheOrigin,
overlap: math.max(0.0, _fixPrecisionError(paintOffset - beforeOffsetPaintExtent)),
remainingPaintExtent: _fixPrecisionError(
constraints.remainingPaintExtent - beforeOffsetPaintExtent,
),
remainingCacheExtent: _fixPrecisionError(
constraints.remainingCacheExtent -
calculateCacheOffset(constraints, from: 0.0, to: scrollOffset),
remainingCacheExtent: math.max(
0.0,
_fixPrecisionError(remainingCacheExtent + cacheExtentCorrection),
),
precedingScrollExtent: scrollOffset + constraints.precedingScrollExtent,
),
@ -349,6 +357,12 @@ class RenderSliverMainAxisGroup extends RenderSliver
maxPaintExtent += childLayoutGeometry.maxPaintExtent;
maxScrollObstructionExtent += childLayoutGeometry.maxScrollObstructionExtent;
paintOffset = math.max(childPaintOffset + childLayoutGeometry.paintExtent, paintOffset);
if (childLayoutGeometry.cacheExtent != 0.0) {
remainingCacheExtent = _fixPrecisionError(
remainingCacheExtent - childLayoutGeometry.cacheExtent - cacheExtentCorrection,
);
cacheOrigin = math.min(correctedCacheOrigin + childLayoutGeometry.cacheExtent, 0.0);
}
child = advance(child);
assert(() {
if (child != null && maxPaintExtent.isInfinite) {

View File

@ -856,6 +856,38 @@ void main() {
expect(renderGroup.geometry!.cacheExtent, 850.0);
});
testWidgets('SliverMainAxisGroup has consistent cacheOrigin', (WidgetTester tester) async {
const Widget item = SizedBox.square(dimension: 50);
await tester.pumpWidget(
MaterialApp(
home: CustomScrollView(
slivers: <Widget>[
SliverMainAxisGroup(
slivers: <Widget>[
const PinnedHeaderSliver(child: SizedBox(height: 500)),
SliverList.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) => item,
),
const SliverToBoxAdapter(child: item),
],
),
],
),
),
);
await tester.scrollUntilVisible(find.byType(SliverToBoxAdapter), 500);
await tester.pumpAndSettle();
final RenderSliver sliverList =
find.byType(SliverList).evaluate().single.findRenderObject()! as RenderSliver;
expect(sliverList.constraints.cacheOrigin, -250.0);
expect(sliverList.constraints.remainingCacheExtent, 1100);
});
testWidgets('SliverMainAxisGroup correctly handles ensureVisible', (WidgetTester tester) async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(