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

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. 深度学习之加载VGG19模型获取特征图

    1.加载VGG19获取图片特征图 # coding = utf-8 import tensorflow as tf import numpy as np import matplotlib.pyplo ...

  2. openstack部署glance

    一.建立glance数据库并且给权限设置第三方登录 mysql -uroot -p0330 CREATE DATABASE glance; GRANT ALL PRIVILEGES ON glance ...

  3. Canal——原理架构及应用场景

    Canal简介 Canal是阿里开源的一款基于Mysql数据库binlog的增量订阅和消费组件,通过它可以订阅数据库的binlog日志,然后进行一些数据消费,如数据镜像.数据异构.数据索引.缓存更新等 ...

  4. 树莓派-Ubuntu Mate开启远程桌面xrdp服务

    树莓派3B+安装Ubuntu Mate后,开启远程桌面xrdp服务可以使用KRDC或mstsc远程登录访问,感觉比vnc要快一些: $ sudo apt install xrdp 安装后重启xrdp服 ...

  5. JAVA 面向对象编程 --自我总结

    子系统 系统结构是指由系统多个子系统组成,以及子系统由多个更小的子系统组成的结构.那么子系统又具备哪些特点呢? 特点: 1.结构的稳定性 :软件在设计阶段,在把一个系统划分成更小的子系统时,设计合理, ...

  6. 逻辑回归(Logistic Regression)二分类原理及python实现

    本文目录: 1. sigmoid function (logistic function) 2. 逻辑回归二分类模型 3. 神经网络做二分类问题 4. python实现神经网络做二分类问题 1. si ...

  7. C++返回对象和返回引用

    我们发现,在C++中,有些成员函数返回的是对象,而有些函数返回的又是引用. 返回对象和返回引用的最主要的区别就是函数原型和函数头. Car run(const Car &)     //返回对 ...

  8. Spring+SpringMvc+Hibernate整合记录

    Spring+SpringMvc+Hibernate+Maven整合各大配置文件记录 1.Idea新建的Maven架构 2.Maven的对象模型的内容 <project xmlns=" ...

  9. (5.3.2)数据库迁移——SSIS包批量导出

    SSIS连接出错 原因 :    ssms 工具 不是 admin 权限 打开的  SSIS包批量导出代码 use msdb go IF OBJECT_ID('msdb.dbo.usp_ExportS ...

  10. DOM、BOM

    DOM DOM 是 W3C(万维网联盟)的标准. DOM 定义了访问 HTML 和 XML 文档的标准: “W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新 ...