一、了解AnimatedWidget
通常我们给一个Widget添加动画的时候都需要监听Animation的addListener()方法,并在这个方法里面不停的调用setState()方法通知Weight进行重绘。
AnimatedWidget是Flutter封装的用于执行动画的助手类。使用它可以使我们创建一个可重用动画的Widget。而且我们也不必关心Weight在什么时候需要重绘,因为AnimatedWidget中会自动调用addListener()和setState()。
AnimatedWidget实际上是一个StatefulWidget,它里面是定义了一套Widget并由外部将执行的动画传进来,然后根据Animation的value使各个Widget做出相应的改变。
Flutter封装了很多AnimatedWidget的助手类。SlideTransition、AlignTransition、PositionedTransition、RelativePositionedTransition等等。
//自定义AnimatedWidget
class CustomAnimatedWidget extendsAnimatedWidget {
CustomAnimatedWidget({Key key, Animationanimation})
:super(key: key, listenable: animation);
Widget build(BuildContext context) {final Animation custom =animation;return newCenter(
child:newContainer(
height: animation.value,
width: animation.value,
child:newContainer(),
),
);
}
}//使用CustomAnimatedWidget
class CustomApp extendsStatefulWidget {
_CustomAppState createState()=> new_CustomAppState();
}class _CustomAppState extends Statewith SingleTickerProviderStateMixin {
AnimationController controller;
Animationanimation;
initState() {super.initState();
controller= newAnimationController(
duration:const Duration(milliseconds: 5000), vsync: this);
animation= new Tween(begin: 0.0, end: 100.0).animate(controller);
controller.forward();
}
Widget build(BuildContext context) {return newCustomAnimatedWidget(animation: animation);
}
dispose() {
controller.dispose();super.dispose();
}
}
View Code
二、了解AnimatedBuilder
AnimatedBuilder相比较AnimatedWidget来说更加纯粹。它不知道如何渲染Widget,也不会管理Animatiion。个人感觉AnimatedWidget是一个执行具体动画的控件,而AnimatedBuilder则是一个执行特定动画的容器。
Flutter中也创建了很多基于AnimatedBuilder的控件。例如:BottomSheet、 PopupMenu、ProgressIndicator、RefreshIndicator、Scaffold、SnackBar、TabBar、TextField。
//自定义CustomAnimatedBuilder
class CustomAnimatedBuilder extendsStatelessWidget {
GrowTransition({this.child, this.animation});finalWidget child;final Animationanimation;
Widget build(BuildContext context) {return newCenter(
child:newAnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {return newContainer(
height: animation.value, width: animation.value, child: child);
},
child: child),
);
}
}//使用CustomAnimatedBuilder
class CustomApp extendsStatefulWidget {
_CustomAppState createState()=> new_CustomAppState();
}class _CustomAppState extends Statewith TickerProviderStateMixin {
Animation animation;
AnimationController controller;
initState() {super.initState();
controller= newAnimationController(
duration:const Duration(milliseconds: 1000), vsync: this);final CurvedAnimation curve =
newCurvedAnimation(parent: controller, curve: Curves.easeIn);
animation= new Tween(begin: 0.0, end: 100.0).animate(curve);
controller.forward();
}
Widget build(BuildContext context) {return newCustomAnimatedBuilder(child: ‘自己的view’, animation: animation);
}
dispose() {
controller.dispose();super.dispose();
}
}
View Code
三、动画示例
1、位移动画
只要Widget能在一定的时间内按照一定的规则位移一定的距离,那边是产生了位移动画。可以通过改变Widget本身的margin,也可以通过改变父容器的padding,也可以通过SlideTransition的Offset产生位移,也可使用Matrix4的transform产生移动(Matrix4解释和使用)。下面看示例:
//位移动画 copy 代码可以直接使用
import 'package:flutter/material.dart';class TransferAnim extendsStatefulWidget {
@override
_TransferAnimState createState()=>_TransferAnimState();
}//ignore: slash_for_doc_comments/*** 这个实现 实际上是改变 父容器的padding/margin完成的*/
class _TransferAnimState extends Statewith SingleTickerProviderStateMixin {
AnimationController _controller;
Animationanim;
AnimationslideTransition;
@overridevoidinitState() {super.initState();
_initAnim();
}
@override
Widget build(BuildContext context) {returnScaffold(
appBar: AppBar(
centerTitle:true,
title: Text("位移动画"),
),
body: Column(
children:[
Expanded(
child: Container(
padding: anim.value,
child: Center(
child: Container(
width:100,
height:50,
margin: ,
color: Colors.amber,
child: Center(
child: Text("位移动画"),
),
),
),
),
),
Expanded(
child: Container(
child: Center(
child: SlideTransition(
position: slideTransition,
child: Container(
width:100,
height:50,
color: Colors.amber,
child: Center(
child: Text("位移动画"),
),
),
),
),
),
),
],
),
);
}void_initAnim() {
_controller=AnimationController(
vsync:this,
duration: Duration(
seconds:3,
),
);
anim= newEdgeInsetsTween(
begin: EdgeInsets.only(left:0, top: 0),
end: EdgeInsets.only(left:100, top: 150),
).animate(_controller);//Offset 这里解释一下,是相对于自己移动的比例倍数
slideTransition = Tween(
begin: Offset(0, 0),
end: Offset(0, 2),
).animate(_controller);
anim.addListener(() {
setState(() {});
});
anim.addStatusListener((status) {
debugPrint('fanlei => $status');switch(status) {caseAnimationStatus.dismissed:
_controller?.forward();break;caseAnimationStatus.forward:break;caseAnimationStatus.reverse:break;caseAnimationStatus.completed:
_controller?.reverse();break;
}
});
_controller?.forward();
}
@overridevoiddispose() {
_controller?.dispose();super.dispose();
}
}
View Code
2、旋转动画
旋转动画就是一个Weight以某个点或者某个坐标轴旋转。可以使用Container()的transform(接受Matrix4)属性,也可以使用RotationTransition()执行旋转动画。下面看示例:
import 'package:flutter/material.dart';class RotateAnim extendsStatefulWidget {
@override
_RotateAnimState createState()=>_RotateAnimState();
}//ignore: slash_for_doc_comments
class _RotateAnimState extends Statewith SingleTickerProviderStateMixin {
AnimationController _controller;
Animationanim;
AnimationdoubleAnim;
@overridevoidinitState() {super.initState();
_initAnim();
}
@override
Widget build(BuildContext context) {returnScaffold(
appBar: AppBar(
centerTitle:true,
title: Text("旋转动画"),
),
body: Container(
child: Column(
children:[
Expanded(
child: Center(
child: Container(
transform: anim.value,
width:200,
height:50,
color: Colors.amber,
child: Center(
child: Text("旋转动画矩阵变换"),
),
),
),
),
Expanded(
child: Center(
child: RotationTransition(
turns: doubleAnim,
child: Container(
width:200,
height:50,
color: Colors.greenAccent,
child: Center(
child: Text("旋转动画Rotation"),
),
),