scrollXY method
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);
}
}