Flutter Animation动画开发之——reverse反向播放
我们知道AnimationController.forward()可以正向播放动画,如果要反向播放动画,可以调用AnimationController.reverse()
踩坑
马上写段代码验证一下,如下代码演示了一个绿色的方块,方向执行动画,大小从200缩小到100
但是理想很美好,现实很残酷,运行后方块一动不动,一直保持最小的状态,也就是宽高100
class AnimationRoute extends StatefulWidget {
@override
AnimationRouteState createState() => AnimationRouteState();
}
class AnimationRouteState extends State<AnimationRoute> with SingleTickerProviderStateMixin {
AnimationController controller;
initState() {
super.initState();
// Controller设置动画时长
// vsync设置一个TickerProvider,当前State 混合了SingleTickerProviderStateMixin就是一个TickerProvider
controller = AnimationController(
lowerBound: 100,
upperBound: 200,
duration: Duration(seconds: 5),
vsync: this //
);
controller.reverse();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (BuildContext ctx, Widget child) {
return Center(
child: Container(
color: Colors.green,
width: controller.value,
height: controller.value,
),
);
}
);
}
@override
void dispose() {
// 释放资源
controller.dispose();
super.dispose();
}
}
解决方法
发现问题,最有效的解决方法就是看源码,我们先看下reverse方法的源码,发现里面有一个可选参数from,该参数如果有传就会设置当前动画的value值为from的值,然后从该值开始反向执行动画。
我猜想可能是AnimationController的value起始值是lowerBound,反向播放的时候也是lowerBound,导致了动画我发播放,因为反向播放时lowerBound是终点值,已开始就是终点值,肯定是无变化的
所以我们一开始可以传入一个from值,比如200或者upperBound,这样就可以从200变化到100
/// Starts running this animation in reverse (towards the beginning).
///
/// Returns a [TickerFuture] that completes when the animation is dismissed.
///
/// The most recently returned [TickerFuture], if any, is marked as having been
/// canceled, meaning the future never completes and its [TickerFuture.orCancel]
/// derivative future completes with a [TickerCanceled] error.
///
/// During the animation, [status] is reported as [AnimationStatus.reverse],
/// which switches to [AnimationStatus.dismissed] when [lowerBound] is
/// reached at the end of the animation.
TickerFuture reverse({ double from }) {
assert(() {
if (duration == null && reverseDuration == null) {
throw FlutterError(
'AnimationController.reverse() called with no default duration or reverseDuration.\n'
'The "duration" or "reverseDuration" property should be set, either in the constructor or later, before '
'calling the reverse() function.'
);
}
return true;
}());
assert(
_ticker != null,
'AnimationController.reverse() called after AnimationController.dispose()\n'
'AnimationController methods should not be used after calling dispose.'
);
_direction = _AnimationDirection.reverse;
if (from != null)
value = from;
return _animateToInternal(lowerBound);
}
所以只需把原来示例里的controller.reverse()改成如下代码即可
controller.reverse(from: controller.upperBound);
或者直接设置200,或者100到200间的任何值也可以,这样可以从中间某个地方反向执行动画
controller.reverse(from: 200);
或者在调用controller.reverse()前先设置value的值
controller.value = 200;
controller.reverse();