layoutChildSequence method Null safety
- {required RenderSliver? child,
- required double scrollOffset,
- required double overlap,
- required double layoutOffset,
- required double remainingPaintExtent,
- required double mainAxisExtent,
- required double crossAxisExtent,
- required GrowthDirection growthDirection,
- required RenderSliver? advance(
- RenderSliver child
- required double remainingCacheExtent,
- required double cacheOrigin}
protected">@protected
Determines the size and position of some of the children of the viewport.
This function is the workhorse of performLayout
implementations in
subclasses.
Layout starts with child
, proceeds according to the advance
callback,
and stops once advance
returns null.
scrollOffset
is the SliverConstraints.scrollOffset to pass the first child. The scroll offset is adjusted by SliverGeometry.scrollExtent for subsequent children.overlap
is the SliverConstraints.overlap to pass the first child. The overlay is adjusted by the SliverGeometry.paintOrigin and SliverGeometry.paintExtent for subsequent children.layoutOffset
is the layout offset at which to place the first child. The layout offset is updated by the SliverGeometry.layoutExtent for subsequent children.remainingPaintExtent
is SliverConstraints.remainingPaintExtent to pass the first child. The remaining paint extent is updated by the SliverGeometry.layoutExtent for subsequent children.mainAxisExtent
is the SliverConstraints.viewportMainAxisExtent to pass to each child.crossAxisExtent
is the SliverConstraints.crossAxisExtent to pass to each child.growthDirection
is the SliverConstraints.growthDirection to pass to each child.
Returns the first non-zero SliverGeometry.scrollOffsetCorrection encountered, if any. Otherwise returns 0.0. Typical callers will call this function repeatedly until it returns 0.0.
Implementation
@protected
double layoutChildSequence({
required RenderSliver? child,
required double scrollOffset,
required double overlap,
required double layoutOffset,
required double remainingPaintExtent,
required double mainAxisExtent,
required double crossAxisExtent,
required GrowthDirection growthDirection,
required RenderSliver? Function(RenderSliver child) advance,
required double remainingCacheExtent,
required double cacheOrigin,
}) {
assert(scrollOffset.isFinite);
assert(scrollOffset >= 0.0);
final double initialLayoutOffset = layoutOffset;
final ScrollDirection adjustedUserScrollDirection =
applyGrowthDirectionToScrollDirection(offset.userScrollDirection, growthDirection);
assert(adjustedUserScrollDirection != null);
double maxPaintOffset = layoutOffset + overlap;
double precedingScrollExtent = 0.0;
while (child != null) {
final double sliverScrollOffset = scrollOffset <= 0.0 ? 0.0 : scrollOffset;
// If the scrollOffset is too small we adjust the paddedOrigin because it
// doesn't make sense to ask a sliver for content before its scroll
// offset.
final double correctedCacheOrigin = math.max(cacheOrigin, -sliverScrollOffset);
final double cacheExtentCorrection = cacheOrigin - correctedCacheOrigin;
assert(sliverScrollOffset >= correctedCacheOrigin.abs());
assert(correctedCacheOrigin <= 0.0);
assert(sliverScrollOffset >= 0.0);
assert(cacheExtentCorrection <= 0.0);
child.layout(SliverConstraints(
axisDirection: axisDirection,
growthDirection: growthDirection,
userScrollDirection: adjustedUserScrollDirection,
scrollOffset: sliverScrollOffset,
precedingScrollExtent: precedingScrollExtent,
overlap: maxPaintOffset - layoutOffset,
remainingPaintExtent: math.max(0.0, remainingPaintExtent - layoutOffset + initialLayoutOffset),
crossAxisExtent: crossAxisExtent,
crossAxisDirection: crossAxisDirection,
viewportMainAxisExtent: mainAxisExtent,
remainingCacheExtent: math.max(0.0, remainingCacheExtent + cacheExtentCorrection),
cacheOrigin: correctedCacheOrigin,
), parentUsesSize: true);
final SliverGeometry childLayoutGeometry = child.geometry!;
assert(childLayoutGeometry.debugAssertIsValid());
// If there is a correction to apply, we'll have to start over.
if (childLayoutGeometry.scrollOffsetCorrection != null) {
return childLayoutGeometry.scrollOffsetCorrection!;
}
// We use the child's paint origin in our coordinate system as the
// layoutOffset we store in the child's parent data.
final double effectiveLayoutOffset = layoutOffset + childLayoutGeometry.paintOrigin;
// `effectiveLayoutOffset` becomes meaningless once we moved past the trailing edge
// because `childLayoutGeometry.layoutExtent` is zero. Using the still increasing
// 'scrollOffset` to roughly position these invisible slivers in the right order.
if (childLayoutGeometry.visible || scrollOffset > 0) {
updateChildLayoutOffset(child, effectiveLayoutOffset, growthDirection);
} else {
updateChildLayoutOffset(child, -scrollOffset + initialLayoutOffset, growthDirection);
}
maxPaintOffset = math.max(effectiveLayoutOffset + childLayoutGeometry.paintExtent, maxPaintOffset);
scrollOffset -= childLayoutGeometry.scrollExtent;
precedingScrollExtent += childLayoutGeometry.scrollExtent;
layoutOffset += childLayoutGeometry.layoutExtent;
if (childLayoutGeometry.cacheExtent != 0.0) {
remainingCacheExtent -= childLayoutGeometry.cacheExtent - cacheExtentCorrection;
cacheOrigin = math.min(correctedCacheOrigin + childLayoutGeometry.cacheExtent, 0.0);
}
updateOutOfBandData(growthDirection, childLayoutGeometry);
// move on to the next child
child = advance(child);
}
// we made it without a correction, whee!
return 0.0;
}