remove method

void remove({
  1. required TKey key,
  2. bool animate = true,
})

Removes a node and all its descendants from the tree.

If animate is true, the nodes will animate out.

Implementation

void remove({required TKey key, bool animate = true}) {
  if (_animationStyle.effectiveEnterExit.duration == Duration.zero) {
    animate = false;
  }
  if (!_hasKey(key)) {
    return;
  }
  // See [insert] for the rationale: flush any deferred visible-order
  // rebuild so the `_order.contains(key)` path gate below reads fresh
  // state. Inside a batch a prior mutation can leave the order dirty,
  // and a stale containment read picks the wrong path in both
  // directions, a row made visible earlier in the batch would degrade
  // to an immediate purge, and a row hidden earlier in the batch would
  // animate out where nobody can see it.
  _ensureVisibleOrder();
  final descendants = _getDescendants(key);
  final nodesToRemove = [key, ...descendants];
  // Capture the parent BEFORE mutation; _removeNodesImmediate purges the
  // node and releases its nid, after which _parentKeyOfKey returns null.
  final parentKey = _parentKeyOfKey(key);
  final affected = <TKey>{};
  if (animate && _order.contains(key)) {
    // Mark nodes as pending deletion so _finalizeAnimation knows to
    // fully remove them (vs just hiding due to parent collapse)
    for (final nodeId in nodesToRemove) {
      _markPendingDeletion(nodeId);
    }
    // Mark all visible nodes as exiting
    for (final nodeId in nodesToRemove) {
      if (_order.contains(nodeId)) {
        _startStandaloneExitAnimation(
          nodeId,
          family: TreeAnimationFamily.enterExit,
        );
      }
    }
    // Animated path: the parent's child list is not mutated until exit
    // animations complete; the raw-count refresh fires from the
    // standalone-tick / group-dismissed sites at purge time. But the
    // parent's LIVE child count changed right here: pending-deletion
    // marking is the moment liveChildCount readers go stale, so the
    // parent row must refresh now as well, along with every sibling
    // whose live position shifted.
    affected.addAll(_siblingRefreshOrToken(parentKey));
  } else {
    _removeNodesImmediate(nodesToRemove);
    _structureGeneration++;
    // Immediate path: the parent's child-list length changed (and its
    // hasChildren may have flipped), and the surviving siblings shifted
    // into new positions.
    affected.addAll(_siblingRefreshOrToken(parentKey));
  }
  _notifyStructural(affectedKeys: affected);
}