syncChildren method
Syncs the children of parentKey to match desired.
Children present under parentKey but absent from desired are removed.
Children in desired but not currently shown are inserted at the correct
index. The order of desired is respected.
If a desired child already exists in the controller under a different parent, it is moved via TreeController.moveNode instead of being freshly inserted, preserving subtree state.
Reparenting note: When called from syncRoots with childrenOf
or from syncMultipleChildren, removal of nodes that are desired
under a different parent is automatically deferred. When calling
syncChildren directly for a single parent, nodes absent from
desired are removed immediately; use syncMultipleChildren when
reparenting across parents.
Reparent through removed root: when invoked from syncRoots and a child is reparented out of a root that is itself being removed in the same sync, the source root's removal is deferred until after this reparent completes. This lets TreeController.moveNode resolve the child's old parent cleanly and stage a FLIP slide against a stable baseline instead of fighting an ancestor-driven exit animation.
Set animate to false to suppress animations.
Implementation
void syncChildren(
TKey parentKey,
List<TreeNode<TKey, TData>> desired, {
bool animate = true,
}) {
_assertNoDuplicateKeys(desired, "syncChildren($parentKey)");
// Silently ignore unknown parents. Without this guard, a release build
// skips TreeController.insert's debug assert and writes _parents[child] =
// parentKey for a ghost parent, creating a zombie subtree unreachable
// from any root and never eligible for _purgeNodeData cleanup.
if (_controller.getNodeData(parentKey) == null) {
return;
}
_controller.runBatch(() {
_syncChildrenImpl(parentKey, desired, animate: animate);
});
}