scrollXY method

dynamic scrollXY(
  1. double x,
  2. double y, {
  3. VoidCallback? onComplete,
})

Implementation

scrollXY(double x, double y, {VoidCallback? onComplete}) {
  // 仅当目标与当前有差异时才处理
  if ((fx != x) || (fy != y)) {
    if (_scrollController.isAnimating) _scrollController.stop();
    _scrollController.duration = Duration(milliseconds: scrollTimeMillis);

    // 零时长保护:避免使用 .forward() 启动长度为 0 的动画(会触发断言),直接写最终值并回调
    if ((_scrollController.duration ?? Duration.zero) <= Duration.zero) {
      fy = y;
      fx = x;
      handlerSaveCacheDataAndNotify(fx, fy);
      try {
        if (onComplete != null) onComplete();
      } catch (_) {}
      return;
    }

    // remove previous listener if any
    if (_scrollListener != null) {
      try {
        _scrollController.removeListener(_scrollListener!);
      } catch (_) {}
      _scrollListener = null;
    }

    // create animations for x and y driven by the same controller
    final animY = Tween(begin: fy, end: y).animate(_scrollController);
    final animX = Tween(begin: fx, end: x).animate(_scrollController);

    _scrollListener = () {
      fy = animY.value.toDouble();
      fx = animX.value.toDouble();
      handlerSaveCacheDataAndNotify(fx, fy);
    };

    _scrollController.addListener(_scrollListener!);

    void _statusHandler(AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        if (_scrollListener != null) {
          try {
            _scrollController.removeListener(_scrollListener!);
          } catch (_) {}
          _scrollListener = null;
        }
        // 调用外部回调(如果传入)
        try {
          if (onComplete != null) onComplete();
        } catch (_) {}
        _scrollController.removeStatusListener(_statusHandler);
      }
    }

    _scrollController.addStatusListener(_statusHandler);
    _scrollController.forward(from: 0.0);
  }
}