一、基本的动画概念和类
- Animation:Flutter动画库中的一个核心类,它生成指导动画的值。
- AnimationController:管理Animation。
- Tween:用来定义动画的执行区间。例如,Tween可能会生成从红到蓝之间的色值,或者从0到255。
- CurvedAnimation:定义一个非线性曲线的动画.
- Listeners:监听动画的运行过程。
- StatusListeners:监听动画状态改变。
1、Animation
Animation对象是指在规定时间和区间内生成动画值的类。Animation对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。 根据Animation对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。
Animation 生成的类型值很多,如:Animation<double>、Animation<Color> 、 Animation<Size>等。
Animation对象有状态。可以通过(value)
属性获取动画的当前值,(isCompleted)判断动画是否完成,(isDismissed)判断动画是否在开始时停止动画
Animation对象本身和UI渲染没有任何关系。
2、AnimationController
AnimationController是一个较为特殊的Animation对象,用来控制管理Animation。但AnimationController是Animation<double>的子类,因此可以在需要Animation对象的任何地方使用。默认情况下,AnimationController在给定的持续时间内线性生成从0.0到1.0的值。
AnimationController controller = new AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
上述是AnimationController 对象的创建方式,构造函数第一个参数是动画执行的时间,第二个vsync传入是防止动画离屏之后继续消耗资源。AnimationController 提供了几个常用的方法。
forward()
:启动动画;reverse({double from}
:倒放动画;reset()
:重置动画,将其设置到动画的开始位置;stop({ bool canceled = true })
:停止动画。
3、Tween
默认情况下,AnimationController的区间是0.0到1.0,如果我们需要不同的范围或者不同类型的区间时,就可以使用Tween来设置不同类型的区间范围。Tween是一个无状态(stateless)对象,需要begin
和end
值。Tween的唯一职责就是定义从开始到结束区间的映射。如颜色区间映射范围:
final Tween<Color> doubleTween = new Tween(begin: Colors.red, end: Colors.blue);
Tween继承自Animatable<T>。Tween对象不存储任何状态,但它提供了一下方法:
- T evaluate(Animation<double> animation):方法将映射函数应用于动画当前值。
- Animation<T> animate(Animation<double> parent):需要传入一个控制器,来获取Animation对象。
4、CurvedAnimation
CurvedAnimation 将动画过程定义为一个非线性曲线,其创建方式如下:
final CurvedAnimation curve =
new CurvedAnimation(parent: controller, curve: Curves.easeIn);
parent:参数为需要传入的控制器,
curve:参数为控制动画的非线性曲线,在Curves中已经定义了很多属性,当然我们也可以自定义。
class ShakeCurve extends Curve {
@override
double transform(double t) {
return math.sin(t * math.PI * 2);
}
}
5、Listeners:监听动画的输出过程。
通过AnimationController对象调用addListener()来实现对动画的输出过程进行监听。 只要动画的值发生变化,就会调用监听器。一个Listener最常见的行为是调用setState()来触发UI重建。
6、StatusListeners:监听动画状态改变。
通过AnimationController对象调用addStatusListener()来实现对动画的状态进行监听。比如动画开始、结束、向前移动或向后移动时会调用StatusListener。
二、基础动画实现
前面已经介绍了基本动画的类和属性,那么我们来看一下平移、旋转、透明、缩放这些基础动画如何实现。
1、平移动画
通过SlideTransition来实现平移动画,附上代码
class Translate extends StatefulWidget {
@override
createState() => TranslateState();
}
class TranslateState extends State<Translate> with TickerProviderStateMixin {
AnimationController controller;
Animation<Offset> animation;
@override
void initState() {
// TODO: implement initState
super.initState();
controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
controller.addStatusListener((status) {
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
animation = Tween(begin: Offset.zero, end: Offset(3.0, 0)).animate(controller);
controller.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
alignment: Alignment.topLeft,
decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
padding: EdgeInsets.all(10),
height: 100,
child: SlideTransition(
position: animation,
child: new Container( width: 80, height: 80, color: Colors.red),
),
);
}
}
2、旋转动画
通过RotationTransition实现旋转动画,附上代码
class Rotation extends StatefulWidget {
@override
createState() => RotationState();
}
class RotationState extends State<Rotation>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> rotation;
@override
void initState() {
// TODO: implement initState
super.initState();
controller = new AnimationController(vsync: this, duration: Duration(seconds: 2));
controller.addStatusListener((state) {
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
rotation = new Tween(begin: 1.0, end: 0.1).animate(controller);
controller.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
padding: EdgeInsets.all(10),
height: 100,
child: RotationTransition(
turns: rotation,
child: new Container( width: 80, height: 80, color: Colors.red, ),
),
);
}
}
3、透明动画
通过FadeTransition实现透明动画
class Alpha extends StatefulWidget {
@override
createState() => AlphaState();
}
class AlphaState extends State<Alpha> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> alpha;
@override
void initState() {
super.initState();
controller = new AnimationController(vsync: this, duration: Duration(seconds: 2));
controller.addStatusListener((state) {
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
alpha = new Tween(begin: 1.0, end: 0.5).animate(controller);
controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
padding: EdgeInsets.all(10),
child: FadeTransition(
opacity: alpha,
child: new Container( width: 100, height: 100, color: Colors.deepPurpleAccent),
),
);
}
}
4、缩放动画
通过ScaleTransition实现缩放动画
class Scale extends StatefulWidget {
@override
createState() => ScaleState();
}
class ScaleState extends State<Scale> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> scale;
@override
void initState() {
super.initState();
controller = new AnimationController(
vsync: this, duration: Duration(seconds: 2));
controller.addStatusListener((state){
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
scale = new Tween(begin: 1.0,end: 0.1).animate(controller);
controller.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
padding: EdgeInsets.all(10),
height: 100,
child: new ScaleTransition(
scale: scale,
child: new Container( width: 80, height: 80, color: Colors.red, ),
),
);
}
}
实现效果:
三、并行动画和串行动画的实现:
1、并行动画
并行动画是指两个及两个以上的动画同时运行。
例如:视图在平移的同时视图从矩形变成圆形。
class Parallel extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ParallelDemoState();
}
}
class ParallelDemoState extends State<Parallel> with SingleTickerProviderStateMixin {
Tween<double> slideTween = Tween(begin: 0.0, end: 300.0);
Tween<double> borderTween = Tween(begin: 0.0, end: 40.0); // 添加边角半径变动范围
Animation<double> slideAnimation;
Animation<double> borderAnimation; // 添加边角半径动画定义
AnimationController controller;
@override
void initState() {
controller = AnimationController(duration: Duration(seconds: 2), vsync: this);
slideAnimation = slideTween.animate(CurvedAnimation(parent: controller, curve: Curves.decelerate));
borderAnimation = borderTween.animate(CurvedAnimation(parent: controller, curve: Curves.linear)); // 定义边角半径动画
controller.addStatusListener((state) {
double dd = slideAnimation.value;
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
controller.addListener((){
setState(() {
});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.topLeft,
decoration: BoxDecoration(border: Border.all(color: Colors.black,width: 2)),
padding: EdgeInsets.all(10),
width: 200,
child: Container(
margin: EdgeInsets.only(left: slideAnimation.value),
width: 80,
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderAnimation.value),
color: Colors.blue,
),
),
);
}
}
2、串行动画
串行动画是指动画一个接一个的执行。
例如:动画平移之后在从矩形变成圆形。
class Sequential extends StatefulWidget {
@override
createState() => SequentialState();
}
class SequentialState extends State<Sequential> with SingleTickerProviderStateMixin {
AnimationController controller;
Tween<double> slideTween = Tween(begin: 0.0, end: 200.0);
Tween<double> borderTween = Tween(begin: 0.0, end: 40.0); // 添加边角半径变动范围
Animation<double> slideAnimation;
Animation<double> borderAnimation;
@override
void initState() {
controller =
AnimationController(duration: Duration(seconds: 2), vsync: this);
slideAnimation = slideTween.animate( CurveTween(curve: Interval(0.0, 0.5, curve: Curves.linear)).animate(controller));
borderAnimation = borderTween.animate(CurveTween(curve: Interval(0.5, 1.0, curve: Curves.linear)).animate(controller));
controller.addStatusListener((state) {
if (controller.isCompleted) {
controller.reverse();
} else if (controller.isDismissed) {
controller.forward();
}
});
controller.addListener((){
setState(() {
});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2),
),
alignment: Alignment.centerLeft,
child: Container(
width: 80,
height: 80,
margin: EdgeInsets.only(left: slideAnimation.value),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderAnimation.value),
// 边角半径的属性上添加动画
color: Colors.blue,
),
),
);
}
}
效果图: