Flutter Animation动画开发之——AnimationStatusListener动画状态监听
源码分析
在之前的文章中我们介绍过Animation的addListener可以用来监听动画每一帧的变化
而如果要监听动画的状态变化,就要用到Animation的void addStatusListener(AnimationStatusListener listener)方法
addStatusListener方法是定义在AnimationLocalStatusListenersMixin中的,Animation抽象类的实现都有withAnimationLocalStatusListenersMixin,比如AnimationController
class AnimationController extends Animation<double>
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
}
我们再看下withAnimationLocalStatusListenersMixin的源码
-
didRegisterListener():在添加动画状态监听前调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现
-
addStatusListener(AnimationStatusListener listener):添加动画状态监听
-
removeStatusListener(AnimationStatusListener listener):移除动画状态监听
-
didUnregisterListener():在移除动画状态监听后调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现
-
notifyStatusListeners(AnimationStatus status):动画状态变化的通知,通知所有注册的AnimationStatusListener
/// A mixin that implements the addStatusListener/removeStatusListener protocol
/// and notifies all the registered listeners when notifyStatusListeners is
/// called.
///
/// This mixin requires that the mixing class provide methods [didRegisterListener]
/// and [didUnregisterListener]. Implementations of these methods can be obtained
/// by mixing in another mixin from this library, such as [AnimationLazyListenerMixin].
mixin AnimationLocalStatusListenersMixin {
final ObserverList<AnimationStatusListener> _statusListeners = ObserverList<AnimationStatusListener>();
/// Called immediately before a status listener is added via [addStatusListener].
///
/// At the time this method is called the registered listener is not yet
/// notified by [notifyStatusListeners].
void didRegisterListener();
/// Called immediately after a status listener is removed via [removeStatusListener].
///
/// At the time this method is called the removed listener is no longer
/// notified by [notifyStatusListeners].
void didUnregisterListener();
/// Calls listener every time the status of the animation changes.
///
/// Listeners can be removed with [removeStatusListener].
void addStatusListener(AnimationStatusListener listener) {
didRegisterListener();
_statusListeners.add(listener);
}
/// Stops calling the listener every time the status of the animation changes.
///
/// Listeners can be added with [addStatusListener].
void removeStatusListener(AnimationStatusListener listener) {
final bool removed = _statusListeners.remove(listener);
if (removed) {
didUnregisterListener();
}
}
/// Calls all the status listeners.
///
/// If listeners are added or removed during this function, the modifications
/// will not change which listeners are called during this iteration.
void notifyStatusListeners(AnimationStatus status) {
final List<AnimationStatusListener> localListeners = List<AnimationStatusListener>.from(_statusListeners);
for (AnimationStatusListener listener in localListeners) {
try {
if (_statusListeners.contains(listener))
listener(status);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'animation library',
context: ErrorDescription('while notifying status listeners for $runtimeType'),
informationCollector: () sync* {
yield DiagnosticsProperty<AnimationLocalStatusListenersMixin>(
'The $runtimeType notifying status listeners was',
this,
style: DiagnosticsTreeStyle.errorProperty,
);
},
));
}
}
}
}
接下来我们在看下AnimationStatus的源码,AnimationStatus是一个枚举类,共定义了如下几种动画状态
- dismissed:回到动画起点处
- forward:从起点往终点方向执行
- reverse:从终点往起点反方向执行
- completed:到达动画终点处
/// The status of an animation
enum AnimationStatus {
/// The animation is stopped at the beginning
dismissed,
/// The animation is running from beginning to end
forward,
/// The animation is running backwards, from end to beginning
reverse,
/// The animation is stopped at the end
completed,
}
示例代码
看完源码分析,接下我我们写一个示例跑一下
一下示例中演示了一个绿色的方块,宽高从100变化到200,由于监听了动画的状态,当动画执行到终点时会反向执行,当反向执行到起点时又会再正向执行,如此循环往复就可以实现无限循环动画(当然,AnimationController.repeat()也可实现动画循环播放)
绿色方块汇总还有两个Text
当动画到达起点时第一个Text显示“起点”,当动画到达终点时第一个Text显示“终点”
当动画往前正向执行时第二个Text显示“正向”,当动画往后反向执行时第二个Text显示“反向”
大家可以直接拷贝如下整段代码运行看下效果
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: AnimationRoute(),
);
}
}
class AnimationRoute extends StatefulWidget {
@override
AnimationRouteState createState() => AnimationRouteState();
}
class AnimationRouteState extends State<AnimationRoute> with SingleTickerProviderStateMixin {
AnimationController controller;
String position = '';
String direction = '';
initState() {
super.initState();
// Controller设置动画时长
// vsync设置一个TickerProvider,当前State 混合了SingleTickerProviderStateMixin就是一个TickerProvider
controller = AnimationController(
lowerBound: 100,
upperBound: 200,
duration: Duration(seconds: 5),
vsync: this //
)..addStatusListener((status){
if (status == AnimationStatus.dismissed) {
controller.forward();
setState(() {
position = '起点';
});
} else if (status == AnimationStatus.forward) {
setState(() {
direction = '正向';
});
} else if (status == AnimationStatus.reverse) {
setState(() {
direction = '反向';
});
} else if (status == AnimationStatus.completed) {
controller.reverse();
setState(() {
position = '终点';
});
}
});
//启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (BuildContext ctx, Widget child) {
return Center(
child: Container(
color: Colors.green,
alignment: Alignment.center,
width: controller.value,
height: controller.value,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(position,
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
),
Text(direction,
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
)
],
),
),
);
}
);
}
@override
void dispose() {
// 释放资源
controller.dispose();
super.dispose();
}
}