animationSlide method
Implementation
animationSlide(double left, double toPositionX, int time, VoidCallback? completed) {
// 停止并重用已有 controller,设置时长
if (_slideController.isAnimating) _slideController.stop();
if (fx == toPositionX) {
// 位置相同则直接回调完成
try {
if (completed != null) completed();
} catch (_) {}
return;
}
_slideController.duration = Duration(milliseconds: time);
// 关键保护:如果时长为 0 或负数,不要调用 .forward(),因为在 Flutter 内部这会触发
// 'simulationDuration > Duration.zero' 的断言。改为立即把位置设置为目标值,并调用完成回调。
// 使用 null 合并以保证在空安全下不会对 null 调用比较运算符。
if ((_slideController.duration ?? Duration.zero) <= Duration.zero) {
// 立即应用最终位置并通知(同步完成)
fx = toPositionX * 1.0;
handlerSaveCacheDataAndNotify(fx, fy);
try {
if (completed != null) completed();
} catch (_) {}
return;
}
// 移除上一次 listener,避免重复添加
if (_slideListener != null) {
try {
_slideAnimation.removeListener(_slideListener!);
} catch (_) {}
_slideListener = null;
}
// tween 从当前 x 到目标位置,确保能从任意起点动画到目标
_slideAnimation = Tween(begin: fx, end: toPositionX * 1.0).animate(_slideController);
// 回弹动画监听:更新 fx 并保存/通知
_slideListener = () {
fx = _slideAnimation.value.toDouble();
handlerSaveCacheDataAndNotify(fx, fy);
};
_slideAnimation.addListener(_slideListener!);
// 状态监听:动画完成后移除 listener 并回调
void _statusHandler(AnimationStatus status) {
if (status == AnimationStatus.completed) {
// remove listener after complete to avoid leak
if (_slideListener != null) {
try {
_slideAnimation.removeListener(_slideListener!);
} catch (_) {}
_slideListener = null;
}
// 调用外部回调(如果有)
try {
if (completed != null) completed();
} catch (_) {}
_slideController.removeStatusListener(_statusHandler);
}
}
_slideController.addStatusListener(_statusHandler);
_slideController.forward(from: 0.0);
}