reorderRoots method

void reorderRoots(
  1. List<TKey> orderedKeys, {
  2. bool animate = true,
  3. Duration? slideDuration,
  4. Curve? slideCurve,
})

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));
}