animateSlideFromOffsets method

void animateSlideFromOffsets(
  1. Map<TKey, ({double x, double y})> priorOffsets,
  2. Map<TKey, ({double x, double y})> currentOffsets, {
  3. Duration? duration,
  4. Curve? curve,
  5. double maxSlideDistance = double.infinity,
})

Starts a FLIP slide animation for every visible node whose position in scroll-space changed between priorOffsets (pre-mutation) and currentOffsets (post-mutation). Produce both with RenderSliverTree.snapshotVisibleOffsets, the first before the structural mutation, the second from inside a WidgetsBinding.addPostFrameCallback after the mutation's layout has run.

A node present in both maps with priorOffsets[key] != currentOffsets[key] receives a new SlideAnimation with startDelta = prior - current. A node only in one map is ignored (it was either added or removed and has its own enter/exit animation for that). A zero delta installs no entry.

Composes with an in-flight slide: if a key already has an entry, its startDelta is replaced with currentDelta_old + (prior - current) and progress is reset to 0.0. This preserves the currently rendered position as the new animation's starting point (no visual jump).

Slide is paint-only: it does not fire the structural-change channel, does not touch layout, and is not counted in hasActiveAnimations. It fires on the animation-listener channel on every tick and on completion; see the slide tick handler for ordering.

Safe to invoke from inside RenderObject.performLayout: the slide is driven by a Ticker whose first callback fires on the next vsync (in SchedulerPhase.transientCallbacks). No listeners fire synchronously from this call, so there is no path that reaches markNeedsLayout/markNeedsPaint on a sliver currently being laid out. The per-entry currentDelta is seeded to startDelta, so the paint pass of the same frame reads the pre-mutation position.

Implementation

void animateSlideFromOffsets(
  Map<TKey, ({double y, double x})> priorOffsets,
  Map<TKey, ({double y, double x})> currentOffsets, {
  Duration? duration,
  Curve? curve,
  double maxSlideDistance = double.infinity,
}) {
  // Null timing resolves to the style's reorderSlide spec.
  _slide.animateFromOffsets(
    priorOffsets,
    currentOffsets,
    duration: duration ?? _animationStyle.reorderSlide.duration,
    curve: curve ?? _animationStyle.reorderSlide.curve,
    maxSlideDistance: maxSlideDistance,
    structuralAnimationsDisabled:
        _animationStyle.reorderSlide.duration == Duration.zero,
  );
}