protected override void debugAssertDoesMeetConstraints() { D.assert(this.geometry.debugAssertIsValid( informationCollector: (information) => { information.AppendLine("The RenderSliver that returned the offending geometry was:"); information.AppendLine(" " + this.toStringShallow(joiner: "\n ")); })); D.assert(() => { if (this.geometry.paintExtent > this.constraints.remainingPaintExtent) { throw new UIWidgetsError( "SliverGeometry has a paintOffset that exceeds the remainingPaintExtent from the constraints.\n" + "The render object whose geometry violates the constraints is the following:\n" + " " + this.toStringShallow(joiner: "\n ") + "\n" + SliverGeometry._debugCompareFloats( "remainingPaintExtent", this.constraints.remainingPaintExtent, "paintExtent", this.geometry.paintExtent) + "The paintExtent must cause the child sliver to paint within the viewport, and so " + "cannot exceed the remainingPaintExtent." ); } return(true); }); }
protected override float updateGeometry() { float?minExtent = this.minExtent; float?minAllowedExtent = constraints.remainingPaintExtent > minExtent ? minExtent : constraints.remainingPaintExtent; float?maxExtent = this.maxExtent; float?paintExtent = maxExtent - _effectiveScrollOffset; float?clampedPaintExtent = paintExtent?.clamp(minAllowedExtent ?? 0.0f, constraints.remainingPaintExtent); float?layoutExtent = maxExtent - constraints.scrollOffset; float?stretchOffset = stretchConfiguration != null? constraints.overlap.abs() : 0.0f; geometry = new SliverGeometry( scrollExtent: maxExtent ?? 0.0f, paintExtent: clampedPaintExtent ?? 0.0f, layoutExtent: layoutExtent?.clamp(0.0f, clampedPaintExtent ?? 0.0f), maxPaintExtent: (maxExtent ?? 0.0f) + (stretchOffset ?? 0.0f), maxScrollObstructionExtent: maxExtent ?? 0.0f, hasVisualOverflow: true ); return(0.0f); }
protected override void debugAssertDoesMeetConstraints() { D.assert( () => { IEnumerable <DiagnosticsNode> infoCollector() { yield return(describeForError("The RenderSliver that returned the offending geometry was")); } return(geometry.debugAssertIsValid( informationCollector: infoCollector)); }); D.assert(() => { if (geometry.paintOrigin + geometry.paintExtent > constraints.remainingPaintExtent) { List <DiagnosticsNode> diagnosticInfo = new List <DiagnosticsNode>(); diagnosticInfo.Add(new ErrorSummary("SliverGeometry has a paintOffset that exceeds the remainingPaintExtent from the constraints.")); diagnosticInfo.Add(describeForError("The render object whose geometry violates the constraints is the following:")); diagnosticInfo.AddRange(SliverGeometry._debugCompareFloats("remainingPaintExtent", constraints.remainingPaintExtent, "paintOrigin + paintExtent", geometry.paintOrigin + geometry.paintExtent)); diagnosticInfo.Add(new ErrorDescription("The paintExtent must cause the child sliver to paint within the viewport, and so " + "cannot exceed the remainingPaintExtent.")); throw new UIWidgetsError(diagnosticInfo); } return(true); }); }
protected override void performLayout() { SliverConstraints constraints = this.constraints; float extent = constraints.remainingPaintExtent - Mathf.Min(constraints.overlap, 0.0f); if (child != null) { child.layout(constraints.asBoxConstraints( minExtent: extent, maxExtent: extent )); } float paintedChildSize = calculatePaintOffset(constraints, from: 0.0f, to: extent); D.assert(paintedChildSize.isFinite()); D.assert(paintedChildSize >= 0.0); geometry = new SliverGeometry( scrollExtent: constraints.viewportMainAxisExtent, paintExtent: paintedChildSize, maxPaintExtent: paintedChildSize, hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0 ); if (child != null) { setChildParentData(child, constraints, geometry); } }
protected override void performLayout() { D.assert(child != null); child.layout(constraints, parentUsesSize: true); if (!offstage) { geometry = child.geometry; } else { geometry = new SliverGeometry( scrollExtent: 0.0f, visible: false, maxPaintExtent: 0.0f); } }
protected override void performLayout() { float?maxExtent = this.maxExtent; layoutChild(constraints.scrollOffset, maxExtent ?? 0.0f); float?paintExtent = maxExtent - constraints.scrollOffset; geometry = new SliverGeometry( scrollExtent: maxExtent ?? 0.0f, paintOrigin: Mathf.Min(constraints.overlap, 0.0f), paintExtent: paintExtent?.clamp(0.0f, constraints.remainingPaintExtent) ?? 0.0f, maxPaintExtent: maxExtent ?? 0.0f, hasVisualOverflow: true ); _childPosition = updateGeometry(); }
protected override void performLayout() { SliverConstraints constraints = this.constraints; float extent = constraints.viewportMainAxisExtent - constraints.precedingScrollExtent; if (child != null) { float childExtent = 0f; switch (constraints.axis) { case Axis.horizontal: childExtent = child.getMaxIntrinsicWidth(constraints.crossAxisExtent); break; case Axis.vertical: childExtent = child.getMaxIntrinsicHeight(constraints.crossAxisExtent); break; } extent = Mathf.Max(extent, childExtent); child.layout(constraints.asBoxConstraints( minExtent: extent, maxExtent: extent )); } D.assert(extent.isFinite(), () => "The calculated extent for the child of SliverFillRemaining is not finite. " + "This can happen if the child is a scrollable, in which case, the " + "hasScrollBody property of SliverFillRemaining should not be set to " + "false." ); float paintedChildSize = calculatePaintOffset(constraints, from: 0.0f, to: extent); D.assert(paintedChildSize.isFinite()); D.assert(paintedChildSize >= 0.0); geometry = new SliverGeometry( scrollExtent: extent, paintExtent: paintedChildSize, maxPaintExtent: paintedChildSize, hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0 ); if (child != null) { setChildParentData(child, constraints, geometry); } }
protected override void performLayout() { if (child == null) { geometry = SliverGeometry.zero; return; } SliverConstraints constraints = this.constraints; child.layout(constraints.asBoxConstraints(), parentUsesSize: true); float childExtent = 0.0f; switch (constraints.axis) { case Axis.horizontal: childExtent = child.size.width; break; case Axis.vertical: childExtent = child.size.height; break; } float paintedChildSize = calculatePaintOffset(constraints, from: 0.0f, to: childExtent); float cacheExtent = calculateCacheOffset(constraints, from: 0.0f, to: childExtent); D.assert(paintedChildSize.isFinite()); D.assert(paintedChildSize >= 0.0f); geometry = new SliverGeometry( scrollExtent: childExtent, paintExtent: paintedChildSize, cacheExtent: cacheExtent, maxPaintExtent: childExtent, hitTestExtent: paintedChildSize, hasVisualOverflow: childExtent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0f ); setChildParentData(child, constraints, geometry); }
protected float updateGeometry() { float?stretchOffset = 0.0f; if (stretchConfiguration != null && _childPosition == 0.0) { stretchOffset += constraints.overlap.abs(); } float?maxExtent = this.maxExtent; float?paintExtent = maxExtent - constraints.scrollOffset; geometry = new SliverGeometry( scrollExtent: maxExtent ?? 0.0f, paintOrigin: Mathf.Min(constraints.overlap, 0.0f), paintExtent: paintExtent?.clamp(0.0f, constraints.remainingPaintExtent) ?? 0.0f, maxPaintExtent: maxExtent + stretchOffset ?? 0.0f, hasVisualOverflow: true// Conservatively say we do have overflow to avoid complexity. ); return(stretchOffset > 0 ? 0.0f :Mathf.Min(0.0f, paintExtent ?? 0.0f - childExtent)); }
protected virtual float updateGeometry() { float stretchOffset = 0.0f; if (stretchConfiguration != null && _childPosition == 0.0) { stretchOffset += constraints.overlap.abs(); } float?maxExtent = this.maxExtent; float?paintExtent = maxExtent - _effectiveScrollOffset; float?layoutExtent = maxExtent - constraints.scrollOffset; geometry = new SliverGeometry( scrollExtent: maxExtent ?? 0.0f, paintOrigin: Mathf.Min(constraints.overlap, 0.0f), paintExtent: paintExtent?.clamp(0.0f, constraints.remainingPaintExtent) ?? 0.0f, layoutExtent: layoutExtent?.clamp(0.0f, constraints.remainingPaintExtent), maxPaintExtent: (maxExtent ?? 0.0f) + stretchOffset, hasVisualOverflow: true ); return(stretchOffset > 0 ? 0.0f : Mathf.Min(0.0f, paintExtent ?? 0.0f - childExtent)); }
protected override void performLayout() { SliverConstraints constraints = this.constraints; float? maxExtent = this.maxExtent; bool overlapsContent = constraints.overlap > 0.0f; layoutChild(constraints.scrollOffset, maxExtent ?? 0.0f, overlapsContent: overlapsContent); float effectiveRemainingPaintExtent = Mathf.Max(0, constraints.remainingPaintExtent - constraints.overlap); float?layoutExtent = (maxExtent - constraints.scrollOffset)?.clamp(0.0f, effectiveRemainingPaintExtent); float stretchOffset = stretchConfiguration != null? constraints.overlap.abs() : 0.0f; geometry = new SliverGeometry( scrollExtent: maxExtent ?? 0.0f, paintOrigin: constraints.overlap, paintExtent: Mathf.Min(childExtent, effectiveRemainingPaintExtent), layoutExtent: layoutExtent, maxPaintExtent: (maxExtent ?? 0.0f) + stretchOffset, maxScrollObstructionExtent: minExtent ?? 0.0f, cacheExtent: layoutExtent > 0.0f ? -constraints.cacheOrigin + layoutExtent : layoutExtent, hasVisualOverflow: true ); }
protected override void performLayout() { SliverConstraints constraints = this.constraints; childManager.didStartLayout(); childManager.setDidUnderflow(false); float itemExtent = this.itemExtent; float scrollOffset = constraints.scrollOffset + constraints.cacheOrigin; D.assert(scrollOffset >= 0.0); float remainingExtent = constraints.remainingCacheExtent; D.assert(remainingExtent >= 0.0); float targetEndScrollOffset = scrollOffset + remainingExtent; BoxConstraints childConstraints = constraints.asBoxConstraints( minExtent: itemExtent, maxExtent: itemExtent ); int firstIndex = getMinChildIndexForScrollOffset(scrollOffset, itemExtent); int?targetLastIndex = targetEndScrollOffset.isFinite() ? getMaxChildIndexForScrollOffset(targetEndScrollOffset, itemExtent) : (int?)null; if (firstChild != null) { int leadingGarbage = _calculateLeadingGarbage(firstIndex); int trailingGarbage = targetLastIndex == null ? 0: _calculateTrailingGarbage(targetLastIndex.Value); collectGarbage(leadingGarbage, trailingGarbage); } else { collectGarbage(0, 0); } if (firstChild == null) { if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) { float max; if (childManager.childCount != null) { max = computeMaxScrollOffset(constraints, itemExtent); } else if (firstIndex <= 0) { max = 0.0f; } else { // We will have to find it manually. int possibleFirstIndex = firstIndex - 1; while ( possibleFirstIndex > 0 && !addInitialChild( index: possibleFirstIndex, layoutOffset: indexToLayoutOffset(itemExtent, possibleFirstIndex) ) ) { possibleFirstIndex -= 1; } max = possibleFirstIndex * itemExtent; } geometry = new SliverGeometry( scrollExtent: max, maxPaintExtent: max ); childManager.didFinishLayout(); return; } } RenderBox trailingChildWithLayout = null; for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) { RenderBox child = insertAndLayoutLeadingChild(childConstraints); if (child == null) { geometry = new SliverGeometry(scrollOffsetCorrection: index * itemExtent); return; } var childParentData = (SliverMultiBoxAdaptorParentData)child.parentData; childParentData.layoutOffset = indexToLayoutOffset(itemExtent, index); D.assert(childParentData.index == index); trailingChildWithLayout = trailingChildWithLayout ?? child; } if (trailingChildWithLayout == null) { firstChild.layout(childConstraints); var childParentData = (SliverMultiBoxAdaptorParentData)firstChild.parentData; childParentData.layoutOffset = indexToLayoutOffset(itemExtent, firstIndex); trailingChildWithLayout = firstChild; } float estimatedMaxScrollOffset = float.PositiveInfinity; for (int index = indexOf(trailingChildWithLayout) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) { RenderBox child = childAfter(trailingChildWithLayout); if (child == null || indexOf(child) != index) { child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout); if (child == null) { estimatedMaxScrollOffset = index * itemExtent; break; } } else { child.layout(childConstraints); } trailingChildWithLayout = child; var childParentData = (SliverMultiBoxAdaptorParentData)child.parentData; D.assert(childParentData.index == index); childParentData.layoutOffset = indexToLayoutOffset(itemExtent, childParentData.index); } int lastIndex = indexOf(lastChild); float leadingScrollOffset = indexToLayoutOffset(itemExtent, firstIndex); float trailingScrollOffset = indexToLayoutOffset(itemExtent, lastIndex + 1); D.assert(firstIndex == 0 || childScrollOffset(firstChild) - scrollOffset <= foundation_.precisionErrorTolerance); D.assert(debugAssertChildListIsNonEmptyAndContiguous()); D.assert(indexOf(firstChild) == firstIndex); D.assert(targetLastIndex == null || lastIndex <= targetLastIndex); estimatedMaxScrollOffset = Mathf.Min( estimatedMaxScrollOffset, estimateMaxScrollOffset( constraints, firstIndex: firstIndex, lastIndex: lastIndex, leadingScrollOffset: leadingScrollOffset, trailingScrollOffset: trailingScrollOffset ) ); float paintExtent = calculatePaintOffset( constraints, from: leadingScrollOffset, to: trailingScrollOffset ); float cacheExtent = calculateCacheOffset( constraints, from: leadingScrollOffset, to: trailingScrollOffset ); float targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; int?targetLastIndexForPaint = targetEndScrollOffsetForPaint.isFinite() ? getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint, itemExtent) : (int?)null; geometry = new SliverGeometry( scrollExtent: estimatedMaxScrollOffset, paintExtent: paintExtent, cacheExtent: cacheExtent, maxPaintExtent: estimatedMaxScrollOffset, hasVisualOverflow: (targetLastIndexForPaint != null && lastIndex >= targetLastIndexForPaint) || constraints.scrollOffset > 0.0 ); if (estimatedMaxScrollOffset == trailingScrollOffset) { childManager.setDidUnderflow(true); } childManager.didFinishLayout(); }
public void setChildParentData(RenderObject child, SliverConstraints constraints, SliverGeometry geometry) { var childParentData = (SliverPhysicalParentData)child.parentData; switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) { case AxisDirection.up: childParentData.paintOffset = new Offset(0.0f, -(geometry.scrollExtent - (geometry.paintExtent + constraints.scrollOffset))); break; case AxisDirection.right: childParentData.paintOffset = new Offset(-constraints.scrollOffset, 0.0f); break; case AxisDirection.down: childParentData.paintOffset = new Offset(0.0f, -constraints.scrollOffset); break; case AxisDirection.left: childParentData.paintOffset = new Offset(-(geometry.scrollExtent - (geometry.paintExtent + constraints.scrollOffset)), 0.0f); break; } }
protected override void performLayout() { float beforePadding = this.beforePadding; float afterPadding = this.afterPadding; float mainAxisPadding = this.mainAxisPadding; float crossAxisPadding = this.crossAxisPadding; if (this.child == null) { this.geometry = new SliverGeometry( scrollExtent: mainAxisPadding, paintExtent: Mathf.Min(mainAxisPadding, this.constraints.remainingPaintExtent), maxPaintExtent: mainAxisPadding ); return; } this.child.layout( this.constraints.copyWith( scrollOffset: Mathf.Max(0.0f, this.constraints.scrollOffset - beforePadding), cacheOrigin: Mathf.Min(0.0f, this.constraints.cacheOrigin + beforePadding), overlap: 0.0f, remainingPaintExtent: this.constraints.remainingPaintExtent - this.calculatePaintOffset(this.constraints, from: 0.0f, to: beforePadding), remainingCacheExtent: this.constraints.remainingCacheExtent - this.calculateCacheOffset(this.constraints, from: 0.0f, to: beforePadding), crossAxisExtent: Mathf.Max(0.0f, this.constraints.crossAxisExtent - crossAxisPadding) ), parentUsesSize: true ); SliverGeometry childLayoutGeometry = this.child.geometry; if (childLayoutGeometry.scrollOffsetCorrection != null) { this.geometry = new SliverGeometry( scrollOffsetCorrection: childLayoutGeometry.scrollOffsetCorrection ); return; } float beforePaddingPaintExtent = this.calculatePaintOffset( this.constraints, from: 0.0f, to: beforePadding ); float afterPaddingPaintExtent = this.calculatePaintOffset( this.constraints, from: beforePadding + childLayoutGeometry.scrollExtent, to: mainAxisPadding + childLayoutGeometry.scrollExtent ); float mainAxisPaddingPaintExtent = beforePaddingPaintExtent + afterPaddingPaintExtent; float beforePaddingCacheExtent = this.calculateCacheOffset( this.constraints, from: 0.0f, to: beforePadding ); float afterPaddingCacheExtent = this.calculateCacheOffset( this.constraints, from: beforePadding + childLayoutGeometry.scrollExtent, to: mainAxisPadding + childLayoutGeometry.scrollExtent ); float mainAxisPaddingCacheExtent = afterPaddingCacheExtent + beforePaddingCacheExtent; float paintExtent = Mathf.Min( beforePaddingPaintExtent + Mathf.Max(childLayoutGeometry.paintExtent, childLayoutGeometry.layoutExtent + afterPaddingPaintExtent), this.constraints.remainingPaintExtent ); this.geometry = new SliverGeometry( scrollExtent: mainAxisPadding + childLayoutGeometry.scrollExtent, paintExtent: paintExtent, layoutExtent: Mathf.Min(mainAxisPaddingPaintExtent + childLayoutGeometry.layoutExtent, paintExtent), cacheExtent: Mathf.Min(mainAxisPaddingCacheExtent + childLayoutGeometry.cacheExtent, this.constraints.remainingCacheExtent), maxPaintExtent: mainAxisPadding + childLayoutGeometry.maxPaintExtent, hitTestExtent: Mathf.Max( mainAxisPaddingPaintExtent + childLayoutGeometry.paintExtent, beforePaddingPaintExtent + childLayoutGeometry.hitTestExtent ), hasVisualOverflow: childLayoutGeometry.hasVisualOverflow ); var childParentData = (SliverPhysicalParentData)this.child.parentData; switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(this.constraints.axisDirection, this.constraints.growthDirection)) { case AxisDirection.up: childParentData.paintOffset = new Offset(this._padding.left, this.calculatePaintOffset(this.constraints, from: this._padding.bottom + childLayoutGeometry.scrollExtent, to: this._padding.bottom + childLayoutGeometry.scrollExtent + this._padding.top)); break; case AxisDirection.right: childParentData.paintOffset = new Offset(this.calculatePaintOffset(this.constraints, from: 0.0f, to: this._padding.left), this._padding.top); break; case AxisDirection.down: childParentData.paintOffset = new Offset(this._padding.left, this.calculatePaintOffset(this.constraints, from: 0.0f, to: this._padding.top)); break; case AxisDirection.left: childParentData.paintOffset = new Offset( this.calculatePaintOffset(this.constraints, from: this._padding.right + childLayoutGeometry.scrollExtent, to: this._padding.right + childLayoutGeometry.scrollExtent + this._padding.left), this._padding.top); break; } D.assert(childParentData.paintOffset != null); D.assert(beforePadding == this.beforePadding); D.assert(afterPadding == this.afterPadding); D.assert(mainAxisPadding == this.mainAxisPadding); D.assert(crossAxisPadding == this.crossAxisPadding); }
protected override void performLayout() { childManager.didStartLayout(); childManager.setDidUnderflow(false); float scrollOffset = constraints.scrollOffset + constraints.cacheOrigin; D.assert(scrollOffset >= 0.0); float remainingExtent = constraints.remainingCacheExtent; D.assert(remainingExtent >= 0.0); float targetEndScrollOffset = scrollOffset + remainingExtent; BoxConstraints childConstraints = constraints.asBoxConstraints(); int leadingGarbage = 0; int trailingGarbage = 0; bool reachedEnd = false; if (firstChild == null) { if (!addInitialChild()) { geometry = SliverGeometry.zero; childManager.didFinishLayout(); return; } } RenderBox leadingChildWithLayout = null, trailingChildWithLayout = null; RenderBox earliestUsefulChild = firstChild; for (float earliestScrollOffset = childScrollOffset(earliestUsefulChild) ?? 0.0f; earliestScrollOffset > scrollOffset; earliestScrollOffset = childScrollOffset(earliestUsefulChild) ?? 0.0f) { earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); if (earliestUsefulChild == null) { var childParentData = (SliverMultiBoxAdaptorParentData)firstChild.parentData; childParentData.layoutOffset = 0.0f; if (scrollOffset == 0.0) { earliestUsefulChild = firstChild; leadingChildWithLayout = earliestUsefulChild; trailingChildWithLayout = trailingChildWithLayout ?? earliestUsefulChild; break; } else { geometry = new SliverGeometry( scrollOffsetCorrection: -scrollOffset ); return; } } else { float firstChildScrollOffset = earliestScrollOffset - paintExtentOf(firstChild); if (firstChildScrollOffset < -foundation_.precisionErrorTolerance) { float correction = 0.0f; while (earliestUsefulChild != null) { D.assert(firstChild == earliestUsefulChild); correction += paintExtentOf(firstChild); earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); } geometry = new SliverGeometry( scrollOffsetCorrection: correction - earliestScrollOffset ); var childParentData = (SliverMultiBoxAdaptorParentData)firstChild.parentData; childParentData.layoutOffset = 0.0f; return; } else { var childParentData = (SliverMultiBoxAdaptorParentData)earliestUsefulChild.parentData; childParentData.layoutOffset = firstChildScrollOffset; D.assert(earliestUsefulChild == firstChild); leadingChildWithLayout = earliestUsefulChild; trailingChildWithLayout = trailingChildWithLayout ?? earliestUsefulChild; } } } D.assert(earliestUsefulChild == firstChild); D.assert(childScrollOffset(earliestUsefulChild) <= scrollOffset); if (leadingChildWithLayout == null) { earliestUsefulChild.layout(childConstraints, parentUsesSize: true); leadingChildWithLayout = earliestUsefulChild; trailingChildWithLayout = earliestUsefulChild; } bool inLayoutRange = true; RenderBox child = earliestUsefulChild; int index = indexOf(child); float endScrollOffset = childScrollOffset(child) + paintExtentOf(child) ?? 0.0f; Func <bool> advance = () => { D.assert(child != null); if (child == trailingChildWithLayout) { inLayoutRange = false; } child = childAfter(child); if (child == null) { inLayoutRange = false; } index += 1; if (!inLayoutRange) { if (child == null || indexOf(child) != index) { child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout, parentUsesSize: true ); if (child == null) { return(false); } } else { child.layout(childConstraints, parentUsesSize: true); } trailingChildWithLayout = child; } D.assert(child != null); var childParentData = (SliverMultiBoxAdaptorParentData)child.parentData; childParentData.layoutOffset = endScrollOffset; D.assert(childParentData.index == index); endScrollOffset = childScrollOffset(child) + paintExtentOf(child) ?? 0.0f; return(true); }; while (endScrollOffset < scrollOffset) { leadingGarbage += 1; if (!advance()) { D.assert(leadingGarbage == childCount); D.assert(child == null); collectGarbage(leadingGarbage - 1, 0); D.assert(firstChild == lastChild); float extent = childScrollOffset(lastChild) + paintExtentOf(lastChild) ?? 0.0f; geometry = new SliverGeometry( scrollExtent: extent, paintExtent: 0.0f, maxPaintExtent: extent ); return; } } while (endScrollOffset < targetEndScrollOffset) { if (!advance()) { reachedEnd = true; break; } } if (child != null) { child = childAfter(child); while (child != null) { trailingGarbage += 1; child = childAfter(child); } } collectGarbage(leadingGarbage, trailingGarbage); D.assert(debugAssertChildListIsNonEmptyAndContiguous()); float?estimatedMaxScrollOffset; if (reachedEnd) { estimatedMaxScrollOffset = endScrollOffset; } else { estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset( constraints, firstIndex: indexOf(firstChild), lastIndex: indexOf(lastChild), leadingScrollOffset: childScrollOffset(firstChild) ?? 0.0f, trailingScrollOffset: endScrollOffset ); D.assert(estimatedMaxScrollOffset >= endScrollOffset - childScrollOffset(firstChild)); } float paintExtent = calculatePaintOffset( constraints, from: childScrollOffset(firstChild) ?? 0.0f, to: endScrollOffset ); float cacheExtent = calculateCacheOffset( constraints, from: childScrollOffset(firstChild) ?? 0.0f, to: endScrollOffset ); float targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; geometry = new SliverGeometry( scrollExtent: estimatedMaxScrollOffset.Value, paintExtent: paintExtent, cacheExtent: cacheExtent, maxPaintExtent: estimatedMaxScrollOffset.Value, hasVisualOverflow: endScrollOffset > targetEndScrollOffsetForPaint || constraints.scrollOffset > 0.0 ); if (estimatedMaxScrollOffset == endScrollOffset) { childManager.setDidUnderflow(true); } childManager.didFinishLayout(); }