performRebuild method
Inspired by SliverMultiBoxAdaptorElement.performRebuild.
This method is called to process any pending updates (for example, new intervals have been added, old intervals have changed state, reordering has started, and so on).
It considers all pending build updates to move each old last rendered child to its new position.
It also calls the _AnimatedRenderSliverMultiBoxAdaptor.didChangeDependencies
method
if a dependency has been changed.
Implementation
@override
void performRebuild() {
_dbgBegin('performRebuild');
_intervalListManager.updates.forEach((e) => _dbgPrint(e.toString()));
if (_didChangeDependencies) {
renderObject.didChangeDependencies(this);
_didChangeDependencies = false;
}
super.performRebuild();
assert(_currentlyUpdatingChildIndex == null);
_currentBeforeChild = null;
try {
// moving children will temporary violate the integrity
renderObject.debugChildIntegrityEnabled = false;
final results = <_PopUpList?, SplayTreeMap<int, _RebuildResult>>{};
final removeList = <Element>[];
final newChildrenMap = <_PopUpList?, SplayTreeMap<int, Element?>>{};
Element? update(Element? element, _ReindexResult r) {
if (r.needsRebuild) {
if (r.discardElement && element != null) {
_dbgPrint(
'updating ${debugElement(element)} discard and update...');
element =
updateChild(element, null, _Slot(r.newIndex!, r.popUpList));
} else {
_dbgPrint('updating ${debugElement(element)} update...');
}
_currentlyUpdatingChildIndex = r.newIndex;
_currentlyUpdatingPopUpList = r.popUpList;
final widget = build(r.newIndex!, popUpList: r.popUpList)!;
element =
updateChild(element, widget, _Slot(r.newIndex!, r.popUpList))!;
_currentlyUpdatingChildIndex = null;
_currentlyUpdatingPopUpList = null;
_dbgPrint(' ....updated into ${debugElement(element)}');
} else {
assert(!r.discardElement);
final newSlot = _Slot(r.newIndex!, r.popUpList);
if (newSlot != element?.slot) {
_dbgPrint(
'updating ${debugElement(element)} slot only: ${element?.slot} -> $newSlot');
}
_currentlyUpdatingChildIndex = r.newIndex;
_currentlyUpdatingPopUpList = r.popUpList;
updateChild(element, element!.widget, newSlot);
_currentlyUpdatingChildIndex = null;
_currentlyUpdatingPopUpList = null;
}
return element;
}
// final offsets = <PopUpList, double>{};
void considerElements(
_PopUpList? popUpList, SplayTreeMap<int, Element?> childElements) {
_dbgBegin('considering popUpList=${popUpList?.debugId}');
_dbgPrint('children=${_debugChildrenList(childElements)}');
_dbgPrint('renderBoxes=${renderObject.debugRenderBoxes(popUpList)}');
for (int? index in childElements.keys.toList()) {
var element = childElements[index]!;
final r = oldIndexToNewIndex(index!, popUpList);
if (r.newIndex == null) {
removeList.add(element);
_dbgPrint(
'element ${debugElement(element)} scheduled for removing');
} else {
_dbgPrint(
'element ${debugElement(element)} from pl(${popUpList?.debugId}):$index -> pl(${r.popUpList?.debugId}}):${r.newIndex}');
results.putIfAbsent(r.popUpList,
() => SplayTreeMap<int, _RebuildResult>())[r.newIndex!] =
_RebuildResult(r, element);
}
}
_dbgEnd();
}
_childElements.forEach((popUpList, elements) {
results.putIfAbsent(
popUpList, () => SplayTreeMap<int, _RebuildResult>());
considerElements(popUpList, elements);
});
for (final popUpList in results.keys) {
final newChildren = newChildrenMap.putIfAbsent(
popUpList, () => SplayTreeMap<int, Element?>());
_currentBeforeChild = null;
_dbgBegin('finalizing popUpList=${popUpList?.debugId}');
for (final index in results[popUpList]!.keys) {
final rr = results[popUpList]![index]!;
final r = rr.result;
var childParentData = _parentDataOf(rr.element);
if (childParentData != null && r.clearLayoutOffset) {
_dbgPrint('clearing layout offset of ${debugElement(rr.element)}');
childParentData.layoutOffset = null;
}
_currentlyUpdatingChildIndex = r.newIndex;
final element = update(rr.element, r)!;
newChildren[r.newIndex!] = element;
childParentData = _parentDataOf(element);
if (r.newIndex == 0) {
childParentData?.layoutOffset = 0.0;
}
if (!childParentData!.keptAlive) {
_currentBeforeChild = element.renderObject as RenderBox?;
}
}
_childElements.putIfAbsent(popUpList, () => newChildren);
_childElements[popUpList] = newChildren;
_dbgPrint(
'result childrenList: ${_debugChildrenList(_childElements[popUpList]!)}');
if (newChildren.isEmpty && popUpList != null) {
_dbgPrint('dismissing popup ${popUpList.debugId}');
_childElements.remove(popUpList);
}
_dbgEnd();
}
_dbgBegin('result RenderBoxes');
for (final popUpList in results.keys) {
_dbgPrint(
'popup ${popUpList?.debugId}: ${renderObject.debugRenderBoxes(popUpList)}');
}
_dbgEnd();
for (final element in removeList) {
_dbgPrint('removing ${debugElement(element)}');
final slot = element.slot as _Slot;
_currentlyUpdatingChildIndex = slot.index;
_currentlyUpdatingPopUpList = slot.popUpList;
updateChild(element, null, slot);
}
} catch (e) {
_dbgPrint('EXCEPTION!!!!');
} finally {
_currentlyUpdatingChildIndex = null;
_currentlyUpdatingPopUpList = null;
renderObject.debugChildIntegrityEnabled = true;
_intervalListManager.clearUpdates();
// renderObject.removeEmptyKeys();
_dbgEnd();
}
}