一、动画关键类的源码分析

1、Animation

Animation没有做什么与动画有关的事情,它只是记录了动画的“状态”、当前的“值”和一些注册回调接口的方法。

abstract class Animation<T> extends Listenable implements ValueListenable<T> {

  const Animation();

  // "值"变化的回调
@override
void addListener(VoidCallback listener); @override
void removeListener(VoidCallback listener);
// 状态回调
void addStatusListener(AnimationStatusListener listener); void removeStatusListener(AnimationStatusListener listener);
// 动画状态
AnimationStatus get status;
// 动画当前“值”
@override
T get value; bool get isDismissed => status == AnimationStatus.dismissed; bool get isCompleted => status == AnimationStatus.completed; //... }

2、Tween

Tween记录了一个区间的begin和end。举个例子来说:begin=100   end=200

    • t=0.1  lerp() = 110
    • t=0.5  lerp() = 150
    • t=1.0  lerp() = 200
class Tween<T extends dynamic> extends Animatable<T> {
//...
// 起始值
T begin;
// 结束值
T end; // 计算在特定区间某个时刻的返回值
// t是[0.0,1.0]在某个时刻的比例系数
@protected
T lerp(double t) {
assert(begin != null);
assert(end != null);
return begin + (end - begin) * t;
}
// 外部调用值的变换
@override
T transform(double t) {
if (t == 0.0)
return begin;
if (t == 1.0)
return end;
return lerp(t);
}
//...
}

我们在使用Tween的时候,必须调用Tween.animate()方法。其animate()方法是Tween继承自Animatable<T>类而来的。

// 创建一个Animation
anim = Tween<Offset>(begin: Offset(0, 0),end: Offset(0, 2),).animate(_controller);
// 位移Tween类中,继承自Animatable<T>类
Animation<T> animate(Animation<double> parent) {
return _AnimatedEvaluation<T>(parent, this);
} class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
//...
@override
final Animation<double> parent;
// 这个变量就是Tween
final Animatable<T> _evaluatable; @override
T get value => _evaluatable.evaluate(parent);
//...
}

由此可以得出animation.value的值来自Tween.evaluate().

3、AnimationController

AnimationController的实现相比较其它的动画核心类来说会比较复杂。那本文章就从两个方面简单分析一下AnimationController的实现。

    • AnimationController的声明
      • AnimationController实现了两个比较重要的Mixin,一个动画值变化的Listener(AnimationLocalListenersMixin),另一个是动画状态改变的Listener(AnimationLocalStatusListenersMixin)。这里就不帖两个Listener的源代码了,感兴趣的可以去Flutter SDK看一下。
// AnimationController的声明
class AnimationController extends Animation<double>
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
    • AnimationController的构造函数

AnimationController可以接收很多参数,其中最重要的就是@required TickerProvider vsync,因为它才是动画动起来的根本原因(下面会讲)。

AnimationController({
double value,
this.duration,// 动画执行时间
this.reverseDuration,// 动画反向执行时的时间长度(默认和duration相同)
this.debugLabel,//debug模式下使用的标签
this.lowerBound = 0.0,// 动画执行完一遍回到的值
this.upperBound = 1.0,// 动画完成的值
this.animationBehavior = AnimationBehavior.normal,// 动画行为(一遍还是重复执行)
@required TickerProvider vsync,
}) : assert(lowerBound != null),
assert(upperBound != null),
assert(upperBound >= lowerBound),
assert(vsync != null),
_direction = _AnimationDirection.forward {
_ticker = vsync.createTicker(_tick);// 计时器
_internalSetValue(value ?? lowerBound);
}

4、CurvedAnimation

CurvedAnimation是一个非线性曲线的Animation,它继承Animation,它与Animation的区别是在取值的时候按照特定非线性曲线函数生成的值。

// 该函数的具体实现方式
@override
double get value {
final Curve activeCurve = _useForwardCurve ? curve : reverseCurve; final double t = parent.value;
if (activeCurve == null)
return t;
if (t == 0.0 || t == 1.0) {
assert(() {
final double transformedValue = activeCurve.transform(t);
final double roundedTransformedValue = transformedValue.round().toDouble();
if (roundedTransformedValue != t) {
throw FlutterError(
'Invalid curve endpoint at $t.\n'
'Curves must map 0.0 to near zero and 1.0 to near one but '
'${activeCurve.runtimeType} mapped $t to $transformedValue, which '
'is near $roundedTransformedValue.'
);
}
return true;
}());
return t;
}
return activeCurve.transform(t);
}

5、SingleTickerProviderStateMixin

我们创建动画的时候,必须要传递一个TickerProvider参数,SingleTickerProviderStateMixin继承TickerProvider。它本身有两个作用:

    • 创建动画计时器。
    • 关联Widget生命周期(实际上给了Ticker)。
@optionalTypeArgs
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
Ticker _ticker;
// 创建Ticker
@override
Ticker createTicker(TickerCallback onTick) {
assert(() {
if (_ticker == null)
return true;
throw FlutterError(
'xxxxxxx'
);
}());
_ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);
return _ticker;
}
//...
@override
void didChangeDependencies() {
// 关联widget的生命周期,实际上传给了Ticker
if (_ticker != null)
_ticker.muted = !TickerMode.of(context);
super.didChangeDependencies();
}
//...
}

二、动画动起来的过程

这时候我们在外面通过anim.addListener(() {setState(() {});});不断的视图层进行重绘,则控件便动了起来。

三、总结

  • 抽象类Animation仅仅保存了动画状态和回调函数。
  • AnimationController和CurvedAnimation都继承Animation。
  • AnimationController是动画的控制器,控制动画的开始和结束,接收动画执行的时间。
  • Tween用于限定动画的值的区间。
  • SingleTickerProviderStateMixin用于创建Ticker和绑定Widget生命周期。
  • Ticker是一个时间定时器,每一个动画帧每一个动画帧都会调用回调函数。

参考文献:1、感谢Flutter中文网提供的资料。2、感谢简书博主

Flutter-动画-原理篇的更多相关文章

  1. OpenGL10-骨骼动画原理篇(3)-Shader版本代码已经上传

    视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440 接上一个例程OpenGL10-骨骼动画原理篇(2),对骨骼动画 ...

  2. OpenGL10-骨骼动画原理篇(2)

    接上一篇的内容,上一篇,简单的介绍了,骨骼动画的原理,给出来一个 简单的例程,这一例程将给展示一个最初级的人物动画,具备多细节内容 以人走路为例子,当人走路的从一个站立开始,到迈出一步,这个过程是 一 ...

  3. OpenGL10-骨骼动画原理篇(1)

    视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440 本例程展示如何建立骨骼动画,有些人叫蒙皮动画 定义如下: 当前 ...

  4. 转:Flutter动画二

    1. 介绍 本文会从代码层面去介绍Flutter动画,因此不会涉及到Flutter动画的具体使用. 1.1 Animation库 Flutter的animation库只依赖两个库,Dart库以及phy ...

  5. Unity3D 骨骼动画原理学习笔记

    最近研究了一下游戏中模型的骨骼动画的原理,做一个学习笔记,便于大家共同学习探讨. ps:最近改bug改的要死要活,博客写的吭哧吭哧的~ 首先列出学习参考的前人的文章,本文较多的参考了其中的表述: 1. ...

  6. 转:Flutter动画一

    1. 动画介绍 动画对于App来说,非常的重要.很多App,正是因为有了动画,所以才会觉得炫酷.移动端的动画库有非常的多,例如iOS上的Pop.web端的animate.css.Android端的An ...

  7. Flutter 动画详解(一)

    本文主要介绍了动画的原理相关概念,对其他平台的动画做了一个简要的梳理,并简要的介绍了Flutter动画的一些知识. 1. 动画介绍 动画对于App来说,非常的重要.很多App,正是因为有了动画,所以才 ...

  8. 《Flutter 动画系列一》25种动画组件超全总结

    动画运行的原理 任何程序的动画原理都是一样的,即:视觉暂留,视觉暂留又叫视觉暂停,人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留的视觉称&q ...

  9. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

    1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...

  10. 《Flutter 动画系列》组合动画

    老孟导读:在前面的文章中介绍了 <Flutter 动画系列>25种动画组件超全总结 http://laomengit.com/flutter/module/animated_1/ < ...

随机推荐

  1. 不知道AI这三点优势,你可能真的要被淘汰

    不知道 AI 这三点优势,你可能真的要被淘汰 我们正处于飞速发展的数字化转型时期,这是由巨大的市场转变驱动的--即人工智能和机器学习. 同时,随着AI 和机器学习技术的普及,从中获益的不仅仅是大型企业 ...

  2. 英特尔®oneAPI简介及动手实验研讨会召集令

    Intel Developer Zone 2019年超级计算大会英特尔正式发布了oneAPI软件行业计划及其beta产品,在上篇文章中我们已为您介绍了oneAPI的基本含义,本文将继续为您介绍oneA ...

  3. python 安装第三方模块的各种方法

    whl包的安装:pip install **.whl(要有pip 和 下载好的whl文件) tar.gz包的安装:python setup.py install (先将tar.gz解压到指定文件夹,在 ...

  4. redhat 5中ifconfig不能使用问题

    ifconfig不能使用问题 输入 ifconfig 命令的绝对路径, ifconfig在是/sbin这个目录下面, 所以在终端输入下列命令就可以运行此命令:/sbin/ifconfig 我们还可以修 ...

  5. USACO 1.1 Your Ride Is Here

    直接模拟 #include<cstdio> #include<cstring> using namespace std; #define MAXN 10 #define MOD ...

  6. vue中使用raphael.js实现地图绘制

    一.效果图 二.在vue中引入raphael.js npm i raphael -S 三.封装一个名为StreetMap的组件,代码如下 <template> <div> &l ...

  7. MySQL: 1006 - Can't create database '***' (errno: 13) 错误 解决方法

    原文连接:https://blog.csdn.net/kexiaoling/article/details/50259569 如果使用root账号登录到数据库create database时提错错误: ...

  8. 【Python】if __name__ == '__main__' 含义解析

    相信大家在看别人的python程序时,可能会在大部分的程序后看到标题这段代码,这里解释下它的意义.总的来说,这句代码的作用就是既能保证当前的.py文件直接运行,也能保证其可以作为模块被其他.py文件导 ...

  9. sql server凭据

    转自:https://blog.csdn.net/kk185800961/article/details/52469170 凭据是包含连接到 SQL Server 外部资源所需的身份验证信息(凭据)的 ...

  10. SQLite进阶-10.约束

    约束 约束是作用于数据表中列上的规则,用于限制表中数据的类型.约束的存在保证了数据库中数据的精确性和可靠性. 约束可以是列级或表级,列级约束作用于单一的列,而表级约束作用于整张数据表. SQLite中 ...