看过不少文章关于写Flutter动画的,可是大多数就是照着文档抄的文章,也有的就是你转发个人,我转发你的。不少文章没有加入本身对知识的理解,不知道为何要这作。为此我打算写一篇本身理解的Flutter动画。bash
flutter中动画分为两类:基于tween或基于物理的。app
“介于二者之间”的简称。在补间动画中,定义了开始点和结束点、时间线以及定义转换时间和速度的曲线。而后由框架计算如何从开始点过渡到结束点。
框架
在基于物理的动画中,运动被模拟为与真实世界的行为类似。例如,当你掷球时,它在何处落地,取决于抛球速度有多快、球有多重、距离地面有多远。 相似地,将链接在弹簧上的球落下(并弹起)与链接到绳子上的球放下的方式也是不一样。
less
它是Animation<double>的子类, 将动画过程定义为一个非线性曲线,也就是说咱们的动画运行的一个路径是怎样的,或者说以一种什么样的形式去表现咱们的动画。ide
它是Animation<double>的子类,是一个特殊的Animation对象,在屏幕刷新的每一帧,就会生成一个新的值。默认状况下,AnimationController在给定的时间段内会线性的生成从0.0到1.0的数字。从类名能够知道其意思:动画控制器,它能够控制动画的状态,监听动画的执行状态,监听动画过程当中产生的值。
动画
当建立一个AnimationController时,须要传递一个vsync
参数,参数的做用就是避免动画的UI不在当前屏幕时消耗没必要要的资源。 经过将SingleTickerProviderStateMixin添加到类定义中,能够将stateful对象做为vsync
的值。举例:当咱们手机接到来电,界面就跳转到接通电话界面,那么来电以前正在运行的动画会暂停。
ui
默认状况下,AnimationController对象产生值的范围是(0.0,1.0)。若是您须要不一样的范围或不一样的数据类型,则可使用Tween来配置动画以生成不一样的范围或数据类型的值。
this
1,main.dart,在body里面放了一个执行动画的组件,主要代码在该组件中spa
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter动画"),
),
body:Animation1() ,
);
}
}
复制代码
2,Animation1.dart组件文件debug
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-28 14:43
///des:
class Animation1 extends StatefulWidget {
@override
_Animation1State createState() => _Animation1State();
}
class _Animation1State extends State<Animation1>
with SingleTickerProviderStateMixin {
Animation animation;
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2000));//建立动画控制器
animation = Tween(begin: 10.0, end: 200.0).animate(animationController); //自定义插值范围
animation.addListener((){ //设置插值监听器,经过setState()从新渲染UI
setState(() {
});
});
animationController.forward(); //启动动画
}
@override
Widget build(BuildContext context) {
return Center(
child:Container(
width: animation.value,
height: animation.value,
color: Colors.redAccent,
),
);
}
@override
void dispose() {
super.dispose();
animationController.dispose(); //释放资源
}
}复制代码
3,说明:
setState()
调用中的动画代码中分离出widget代码。AnimatedWidget不须要维护一个State对象来保存动画。1,Animation2.dart组件文件
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-28 14:43
///des:
class Animation2 extends StatefulWidget {
@override
_Animation2tate createState() => _Animation2tate();
}
class _Animation2tate extends State<Animation2>
with SingleTickerProviderStateMixin {
Animation animation;
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 2000));//建立动画控制器
animation = Tween(begin: 10.0, end: 200.0).animate(animationController); //自定义插值范围
animationController.forward(); //启动动画
}
@override
Widget build(BuildContext context) {
return Center(
child:CustomWidget(animation: animation),
);
}
@override
void dispose() {
super.dispose();
animationController.dispose(); //释放资源
}
}
//须要执行动画的组件封装在这里
class CustomWidget extends AnimatedWidget{
CustomWidget({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Container(
width: animation.value,
height: animation.value,
color: Colors.redAccent,
);
}
}复制代码
2,说明:
咱们把动画组件中的child换成了CustomWidget,去掉了动画的监听和状态的刷新。该替换组件是继承自AnimatedWidget的,它接收一个Animation对象。AnimatedWidget(基类)中会自动调用addListener()和setState()方法,完成UI的刷新,此时动画执行与以前同样。
为何说是简化了操做呢,咱们能够这么理解,原先咱们须要本身监听动画执行管理状态,此时咱们只须要定义出动画规则,把规则交给AnimatedWidget就好了,其余的咱们不用管了,让它本身去完成动画的状态管理与UI刷新。
另外,咱们这样写的话,达到了动画复用的效果,从这个层面上来看也能够理解为简化了动画。
感受从总体上面来看,这个简化有点牵强附会,我暂时只能这样理解了,读者有更好的理解能够下方留言,谢谢
前面两种动画实现中,咱们的插值都侵入到了组件的内部,看下面代码。
return Container(
width: animation.value,
height: animation.value,
color: Colors.redAccent,
);复制代码
若是此时咱们要更换这个组件怎么办,好比咱们想把动画对象(须要执行动画的组件)换成一张图片,又或者是其余的,那咱们不得不去修改这个动画对象,是否是很麻烦,并且复用程度很低。那么咱们有没有什么办法把动画对象,动画规则都给分离开来,各司其职。此时就用到了AnimatedBuilder。它经过匿名构造器按照动画插值从新构建UI,自动管理动画状态与刷新。
另外,这种刷新是局部的,它只针对于动画对象作的刷新,而不是应用到整个页面,因此我认为这种刷新比上面两种节省资源。
Animation3.dart组件文件
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-28 17:29
///des:
class Animation3 extends StatefulWidget {
@override
_Animation3State createState() => _Animation3State();
}
class _Animation3State extends State<Animation3> with SingleTickerProviderStateMixin{
Animation animation;
AnimationController controller;
initState() {
super.initState();
controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); //动画控制器
animation = new Tween(begin: 0.0, end: 300.0).animate(controller); //自定义插值范围
controller.forward();//启动动画
}
@override
Widget build(BuildContext context) {
return GrowBuild(child: MyContainer(), animation: animation);
}
dispose() {
controller.dispose();
super.dispose();
}
}
//经过AnimatedBuilder实现动画规则与动画对象分离
class GrowBuild extends StatelessWidget {
GrowBuild({this.child, this.animation});
final Widget child;
final Animation<double> animation;
Widget build(BuildContext context) {
return new Center(
child: new AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) { //匿名构造器根据动画插值从新构建child,而后从新渲染
return new Container(
height: animation.value, width: animation.value, child: child);
},
child: child), //将从新渲染后的child回显
);
}
}
//动画对象
class MyContainer extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
width: 100.0,
height: 200.0,
color: Colors.redAccent,
);
}
}
复制代码
以上是我的对Flutter动画基础的一点看法,不必定全对。若有错误,烦请指正。
另外,读者在有些地方有本身的看法能够留言,互相探讨,谢谢。