layoutChildSequence method

  1. @protected
double layoutChildSequence({
  1. required RenderSliver? child,
  2. required double scrollOffset,
  3. required double overlap,
  4. required double layoutOffset,
  5. required double remainingPaintExtent,
  6. required double mainAxisExtent,
  7. required double crossAxisExtent,
  8. required GrowthDirection growthDirection,
  9. required RenderSliver? advance(
    1. RenderSliver child
    ),
  10. required double remainingCacheExtent,
  11. required double cacheOrigin,
})

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.

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);
  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;
}