您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

218 行
8.8 KiB

using System;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.rendering {
public class RenderSliverList : RenderSliverMultiBoxAdaptor {
public RenderSliverList(
RenderSliverBoxChildManager childManager = null
) : base(childManager: childManager) {
}
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);
earliestScrollOffset > scrollOffset;
earliestScrollOffset = childScrollOffset(earliestUsefulChild)) {
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 < -SliverGeometry.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);
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);
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);
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),
trailingScrollOffset: endScrollOffset
);
D.assert(estimatedMaxScrollOffset >= endScrollOffset - childScrollOffset(firstChild));
}
float paintExtent = calculatePaintOffset(
constraints,
from: childScrollOffset(firstChild),
to: endScrollOffset
);
float cacheExtent = calculateCacheOffset(
constraints,
from: childScrollOffset(firstChild),
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();
}
}
}