Unverified Commit f97978f9 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Re-use methods to calculate leading and trailing garbage in RenderSliverMultiBoxAdaptor (#143884)

My RenderSliverMultiBoxAdaptor/RenderSliverFixedExtentList/RenderSliverVariedExtentList yak shave continues.

I've been subclassing RenderSliverVariedExtentList for SliverTree and have found some opportunities for clean up.
There is a larger clean up I'd like to do, but this week SliverTree comes first. 

I noticed these methods were getting repeated 🔁, and I was about to repeat them again 🔁 for the tree, so I figured bumping them up to the base class was better than continuing to copy-paste the same methods.
parent c3e786f3
......@@ -236,26 +236,6 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
}
}
int _calculateLeadingGarbage(int firstIndex) {
RenderBox? walker = firstChild;
int leadingGarbage = 0;
while (walker != null && indexOf(walker) < firstIndex) {
leadingGarbage += 1;
walker = childAfter(walker);
}
return leadingGarbage;
}
int _calculateTrailingGarbage(int targetLastIndex) {
RenderBox? walker = lastChild;
int trailingGarbage = 0;
while (walker != null && indexOf(walker) > targetLastIndex) {
trailingGarbage += 1;
walker = childBefore(walker);
}
return trailingGarbage;
}
int _getChildIndexForScrollOffset(double scrollOffset, ItemExtentBuilder callback) {
if (scrollOffset == 0.0) {
return 0;
......@@ -323,8 +303,8 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
getMaxChildIndexForScrollOffset(targetEndScrollOffset, deprecatedExtraItemExtent) : null;
if (firstChild != null) {
final int leadingGarbage = _calculateLeadingGarbage(firstIndex);
final int trailingGarbage = targetLastIndex != null ? _calculateTrailingGarbage(targetLastIndex) : 0;
final int leadingGarbage = calculateLeadingGarbage(firstIndex: firstIndex);
final int trailingGarbage = targetLastIndex != null ? calculateTrailingGarbage(lastIndex: targetLastIndex) : 0;
collectGarbage(leadingGarbage, trailingGarbage);
} else {
collectGarbage(0, 0);
......
......@@ -597,8 +597,8 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
final int? targetLastIndex = targetEndScrollOffset.isFinite ?
layout.getMaxChildIndexForScrollOffset(targetEndScrollOffset) : null;
if (firstChild != null) {
final int leadingGarbage = _calculateLeadingGarbage(firstIndex);
final int trailingGarbage = targetLastIndex != null ? _calculateTrailingGarbage(targetLastIndex) : 0;
final int leadingGarbage = calculateLeadingGarbage(firstIndex: firstIndex);
final int trailingGarbage = targetLastIndex != null ? calculateTrailingGarbage(lastIndex: targetLastIndex) : 0;
collectGarbage(leadingGarbage, trailingGarbage);
} else {
collectGarbage(0, 0);
......@@ -708,24 +708,4 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
}
childManager.didFinishLayout();
}
int _calculateLeadingGarbage(int firstIndex) {
RenderBox? walker = firstChild;
int leadingGarbage = 0;
while (walker != null && indexOf(walker) < firstIndex) {
leadingGarbage += 1;
walker = childAfter(walker);
}
return leadingGarbage;
}
int _calculateTrailingGarbage(int targetLastIndex) {
RenderBox? walker = lastChild;
int trailingGarbage = 0;
while (walker != null && indexOf(walker) > targetLastIndex) {
trailingGarbage += 1;
walker = childBefore(walker);
}
return trailingGarbage;
}
}
......@@ -504,6 +504,48 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
return null;
}
/// Returns the number of children preceding the `firstIndex` that need to be
/// garbage collected.
///
/// See also:
///
/// * [collectGarbage], which takes the leading and trailing number of
/// children to be garbage collected.
/// * [calculateTrailingGarbage], which similarly returns the number of
/// trailing children to be garbage collected.
@visibleForTesting
@protected
int calculateLeadingGarbage({required int firstIndex}) {
RenderBox? walker = firstChild;
int leadingGarbage = 0;
while (walker != null && indexOf(walker) < firstIndex) {
leadingGarbage += 1;
walker = childAfter(walker);
}
return leadingGarbage;
}
/// Returns the number of children following the `lastIndex` that need to be
/// garbage collected.
///
/// See also:
///
/// * [collectGarbage], which takes the leading and trailing number of
/// children to be garbage collected.
/// * [calculateLeadingGarbage], which similarly returns the number of
/// leading children to be garbage collected.
@visibleForTesting
@protected
int calculateTrailingGarbage({required int lastIndex}) {
RenderBox? walker = lastChild;
int trailingGarbage = 0;
while (walker != null && indexOf(walker) > lastIndex) {
trailingGarbage += 1;
walker = childBefore(walker);
}
return trailingGarbage;
}
/// Called after layout with the number of children that can be garbage
/// collected at the head and tail of the child list.
///
......@@ -513,6 +555,13 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
/// This method also collects any children that were previously kept alive but
/// are now no longer necessary. As such, it should be called every time
/// [performLayout] is run, even if the arguments are both zero.
///
/// See also:
///
/// * [calculateLeadingGarbage], which can be used to determine
/// `leadingGarbage` here.
/// * [calculateTrailingGarbage], which can be used to determine
/// `trailingGarbage` here.
@protected
void collectGarbage(int leadingGarbage, int trailingGarbage) {
assert(_debugAssertChildListLocked());
......
......@@ -346,6 +346,29 @@ void main() {
);
expect(maxScrollOffset, 90.0);
});
test('RenderSliverMultiBoxAdaptor has calculate leading and trailing garbage', () {
final List<RenderBox> children = <RenderBox>[
RenderSizedBox(const Size(400.0, 100.0)),
RenderSizedBox(const Size(400.0, 100.0)),
RenderSizedBox(const Size(400.0, 100.0)),
];
final TestRenderSliverBoxChildManager childManager = TestRenderSliverBoxChildManager(
children: children,
);
final RenderSliverFixedExtentList sliver = childManager.createRenderSliverFixedExtentList(30.0);
final RenderViewport root = RenderViewport(
crossAxisDirection: AxisDirection.right,
offset: ViewportOffset.zero(),
cacheExtent: 100,
children: <RenderSliver>[ sliver ],
);
layout(root);
// There are 3 children. If I want to garbage collect based on keeping only
// the middle child, then I should get 1 for leading and 1 for trailing.
expect(sliver.calculateLeadingGarbage(firstIndex: 1), 1);
expect(sliver.calculateTrailingGarbage(lastIndex: 1), 1);
});
}
int testGetMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment