isNodeRetained method

bool isNodeRetained(
  1. TKey id
)

Whether the given node is retained by the current layout, i.e. it is explicitly pinned, in the cache region, a sticky header, or a phantom-exit ghost mid-slide. Used by the element to decide whether an off-screen child can be evicted. O(1) (Map containsKey + Set lookup), no allocation.

Implementation

bool isNodeRetained(TKey id) {
  if (_pinnedNodes.contains(id)) return true;
  // Phantom-exit ghosts: retain past visible-order purge so their
  // slide can finish. Removed from _phantomExitGhosts when their
  // slide settles, after which the next stale eviction will release
  // the render box normally.
  final ghosts = _phantomExitGhosts;
  if (ghosts != null && ghosts.containsKey(id)) return true;
  // Edge-anchor exit ghosts: retain so the parallel ghost paint pass
  // can render them. The row IS in visibleNodes (its structural is
  // still in the tree) but may sit outside the cache region; without
  // explicit retention here, layout admission would evict the child
  // and the ghost paint pass would have nothing to paint.
  if (_composer.ghosts.entryFor(id) != null) return true;
  final nid = _controller.nidOf(id);
  if (nid < 0) return false;
  if (nid < _inCacheRegionByNid.length && _inCacheRegionByNid[nid] != 0) {
    return true;
  }
  // Mid-flight FLIP slide: the engine has a live slide entry for this
  // nid (currentDelta != 0 in either axis is the externally-observable
  // proxy, the engine clears entries whose composedY/X both reach 0
  // and the lerp only crosses zero at completion). Retain so paint can
  // continue to render the row at `structural + slideDelta` even when
  // the post-mutation structural Y has moved outside the cache region
  // (e.g. a re-moveTo mid-slide pushed the row far off-screen). Without
  // this, stale-eviction (gated only by `hasActiveAnimations`, which
  // excludes slides, see [TreeController.hasActiveAnimations] doc)
  // would drop the render box mid-slide, leaving the engine ticking a
  // slide for a child that no longer exists, so the row appears stuck
  // / vanishes during its visible transit through the viewport. Once
  // the slide settles (delta=0), this branch falls through and the
  // next eviction releases the box normally.
  // FLIP-only, for the reason spelled out in
  // `SliverTreeElement._scheduleStaleEviction`: a held preview offset
  // never decays, so the composed read retained every row a preview
  // touched for the whole drag. A preview-shifted row is admitted by
  // layout instead, so the cache-region check above already covers it.
  //
  // In fact the cache-region check above covers a mid-slide row too,
  // because overreach widens that region by the composed bound. This
  // clause is the belt to that braces; see the eviction gate's doc for
  // the measurement.
  if (_controller.getFlipSlideDeltaNid(nid) != 0.0 ||
      _controller.getSlideDeltaXNid(nid) != 0.0) {
    return true;
  }
  return _sticky.isSticky(nid);
}