reorderRoots method
void
reorderRoots(})
Reorders the root nodes to match orderedKeys.
orderedKeys must contain exactly the current live (non-pending-deletion)
root keys, with no duplicates; violating that throws an
ArgumentError. Expansion state, animation state, and measured
extents are preserved. Pending-deletion roots are appended after the
live roots.
When animate is true, shifted roots get a paint-only FLIP slide
over slideDuration/slideCurve; both default to the controller's
animationStyle reorderSlide spec when omitted.
Implementation
void reorderRoots(
List<TKey> orderedKeys, {
bool animate = true,
Duration? slideDuration,
Curve? slideCurve,
}) {
final pendingRoots = <TKey>[];
final liveRootSet = <TKey>{};
for (final k in _roots) {
if (_isPendingDeletion(k)) {
pendingRoots.add(k);
} else {
liveRootSet.add(k);
}
}
// Validate in all build modes: an `assert` here would be stripped in
// release and silently corrupt `_roots` (duplicated entries, lost subtrees,
// references to unknown keys).
if (orderedKeys.length != liveRootSet.length ||
orderedKeys.toSet().length != orderedKeys.length ||
!liveRootSet.containsAll(orderedKeys)) {
throw ArgumentError.value(
orderedKeys,
"orderedKeys",
"must contain exactly the current live root keys with no duplicates",
);
}
// Stage the FLIP slide baseline BEFORE mutating so shifted roots slide to
// their new positions (roots are depth-0 and the _markVisibleOrderDirty
// below always fires, so the next layout consumes the baseline).
// Family kill switch: a zero reorderSlide spec disables reorder
// slides even for explicit per-call durations (the engine also
// snaps a staged zero duration on its own).
if (animate && _animationStyle.reorderSlide.duration != Duration.zero) {
// Null timing resolves to the style's reorderSlide spec.
_stageSlideBaselineOnHosts(
duration: slideDuration ?? _animationStyle.reorderSlide.duration,
curve: slideCurve ?? _animationStyle.reorderSlide.curve,
);
}
_roots
..clear()
..addAll(orderedKeys)
..addAll(pendingRoots);
// Raw sibling-list writes above; invalidate cached live indices.
_liveIndexCache.bump();
_markVisibleOrderDirty();
// `nodeBuilder` itself takes (context, key, depth) and so is unaffected
// by order, but a row can read its own position among its siblings
// from the controller (and the declarative layer's node view exposes
// it), so a reorder does change what the reordered rows render. The
// sliver's layout repositions elements in place either way.
_notifyStructural(affectedKeys: _siblingRefreshOrToken(null));
}