animateScrollToKey method

Future<bool> animateScrollToKey(
  1. TKey key, {
  2. required ScrollController scrollController,
  3. Duration duration = const Duration(milliseconds: 300),
  4. Curve curve = Curves.easeInOut,
  5. double alignment = 0.0,
  6. AncestorExpansionMode ancestorExpansion = AncestorExpansionMode.immediate,
  7. double extentEstimator(
    1. TKey key
    )?,
  8. double sliverBaseOffset = 0.0,
})

Animates scrollController to reveal key. See TreeController.animateScrollToKey for the full contract.

Implementation

Future<bool> animateScrollToKey(
  TKey key, {
  required ScrollController scrollController,
  Duration duration = const Duration(milliseconds: 300),
  Curve curve = Curves.easeInOut,
  double alignment = 0.0,
  AncestorExpansionMode ancestorExpansion = AncestorExpansionMode.immediate,
  double Function(TKey key)? extentEstimator,
  double sliverBaseOffset = 0.0,
}) async {
  assert(
    alignment >= 0.0 && alignment <= 1.0,
    "alignment must be between 0.0 and 1.0",
  );

  if (!scrollController.hasClients) return false;

  // Collect any ancestors that are currently collapsed.
  final collapsedAncestors = <TKey>[];
  {
    TKey? current = _controller.getParent(key);
    while (current != null) {
      if (!_controller.isExpanded(current)) collapsedAncestors.add(current);
      current = _controller.getParent(current);
    }
  }

  // Animated concurrent expand+scroll. Falls back to the standard path
  // when there's nothing to expand or when animations are disabled.
  if (ancestorExpansion == AncestorExpansionMode.animated &&
      collapsedAncestors.isNotEmpty &&
      _controller.animationDuration != Duration.zero &&
      duration != Duration.zero) {
    return _animatedConcurrentScroll(
      key: key,
      ancestors: collapsedAncestors,
      scrollController: scrollController,
      duration: duration,
      curve: curve,
      alignment: alignment,
      extentEstimator: extentEstimator,
      sliverBaseOffset: sliverBaseOffset,
    );
  }

  if (ancestorExpansion == AncestorExpansionMode.none &&
      collapsedAncestors.isNotEmpty) {
    return false;
  }

  if (collapsedAncestors.isNotEmpty) {
    ensureAncestorsExpanded(key);
  }

  final sliverOffset = scrollOffsetOf(key, extentEstimator: extentEstimator);
  if (sliverOffset == null) return false;

  final position = scrollController.position;
  final viewportExtent = position.viewportDimension;
  final rowExtent = extentOf(key, extentEstimator: extentEstimator);
  final rawTarget =
      sliverBaseOffset +
      sliverOffset -
      (viewportExtent - rowExtent) * alignment;
  final clamped = rawTarget.clamp(
    position.minScrollExtent,
    position.maxScrollExtent,
  );

  if (duration == Duration.zero) {
    position.jumpTo(clamped);
  } else {
    await position.animateTo(clamped, duration: duration, curve: curve);
  }
  return true;
}