if (firstChild == null) { // 如果没有 children if (!addInitialChild()) { // There are no children. geometry = SliverGeometry.zero; childManager.didFinishLayout(); return; } } // 至少存在一个 children // leading 头部,trailing 尾部 RenderBox leadingChildWithLayout, trailingChildWithLayout; // Find the last child that is at or before the scrollOffset. RenderBox earliestUsefulChild = firstChild; for (double earliestScrollOffset = childScrollOffset(earliestUsefulChild); earliestScrollOffset > scrollOffset; earliestScrollOffset = childScrollOffset(earliestUsefulChild)) { // 在头部插入新的 children earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); if (earliestUsefulChild == null) { final SliverMultiBoxAdaptorParentData childParentData = firstChild .parentData; childParentData.layoutOffset = 0.0; if (scrollOffset == 0.0) { earliestUsefulChild = firstChild; leadingChildWithLayout = earliestUsefulChild; trailingChildWithLayout ??= earliestUsefulChild; break; } else { // We ran out of children before reaching the scroll offset. // We must inform our parent that this sliver cannot fulfill // its contract and that we need a scroll offset correction. geometry = SliverGeometry( scrollOffsetCorrection: -scrollOffset, ); return; } } finaldouble firstChildScrollOffset = earliestScrollOffset - paintExtentOf(firstChild); if (firstChildScrollOffset < -precisionErrorTolerance) { // 双精度错误 } final SliverMultiBoxAdaptorParentData childParentData = earliestUsefulChild .parentData; // 更新 parentData childParentData.layoutOffset = firstChildScrollOffset; assert(earliestUsefulChild == firstChild); // 更新头尾 leadingChildWithLayout = earliestUsefulChild; trailingChildWithLayout ??= earliestUsefulChild; }
上面的代码是处理以下这种情况,即 earliestScrollOffset > scrollOffset,即头部的 children 和 scrollOffset 之间有空间,没有填充。画个简单的图形。
// Find the first child that ends after the scroll offset. while (endScrollOffset < scrollOffset) { // 记录需要回收的项目 leadingGarbage += 1; if (!advance()) { assert(leadingGarbage == childCount); assert(child == null); // we want to make sure we keep the last child around so we know the end scroll offset collectGarbage(leadingGarbage - 1, 0); assert(firstChild == lastChild); finaldouble extent = childScrollOffset(lastChild) + paintExtentOf(lastChild); geometry = SliverGeometry( scrollExtent: extent, paintExtent: 0.0, maxPaintExtent: extent, ); return; } }
不在可见视图,不在缓存区域的,记录头部需要回收的。
1 2 3 4 5 6 7
// Now find the first child that ends after our end. while (endScrollOffset < targetEndScrollOffset) { if (!advance()) { reachedEnd = true; break; } }
从上往下滚动时,调用 advance() 不断在底部插入新的 child。
1 2 3 4 5 6 7 8 9 10
// Finally count up all the remaining children and label them as garbage. if (child != null) { child = childAfter(child); while (child != null) { trailingGarbage += 1; child = childAfter(child); } } // 回收 collectGarbage(leadingGarbage, trailingGarbage);