1. 介绍

本文会从代码层面去介绍Flutter动画,因此不会涉及到Flutter动画的具体使用。

1.1 Animation库

Flutter的animation库只依赖两个库,Dart库以及physics库。animation是采用Dart编写的,所以依赖Dart库是很正常的。physics库是什么呢?

Simple one-dimensional physics simulations, such as springs, friction, and gravity, for use in user interface animations.

physics库是一个简单的物理模拟的库,包含弹簧、阻尼、重力等物理效果。前篇文章介绍过Flutter动画,Flutter动画两个分类中的一个就是基于物理的动画(Physics-based animation)。所以可以猜测出animation库中有一部分代码,是实现了另一种动画--补间动画(Tween Animation)。

通过这种库的划分,也可以大致猜测出,基于物理动画的库是后续添加的。这说明了什么呢?

  • 补间动画是现代移动端相对基础的动画类型,这个是必须的;
  • 基于物理动画是在体验上的改善添加上去的,大致可以猜测出为iOS端的体验优化;

1.2 Physics库

Flutter基于物理的动画,实际上是相当简单的。目前实现了弹簧、阻尼、重力三种物理效果,整个库的代码量也不多。详细的代码在下面的部分介绍,在此处,我们先来说下基于物理的动画库的原理。

基于物理的动画,给我们的感觉会更真实,这是因为其更符合人们日常生活的感官。例如做一个球体下落的动画,如果是匀速的下落,给人的感觉会不够真实,实际的生活经验告诉我们,球体自由下落应该是会有先慢后快的一个过程。如果让我们自己去实现这么一个动画效果,我们会怎么去处理呢?

高中物理我们学习过自由落体相关的概念,其中的位移计算公式:

s = 1/2 * g * t * t

从公式中我们知道,自由落体的位移跟时间不是线性关系。我们可以根据这个公式,来实时的计算出位移来。

如果是摩擦阻尼或者弹簧呢,也都有相关的物理公式,我们所谓的基于物理的动画库,也就是基于此类公式来实现的,本质上还是补间动画,只不过过程遵循物理规律比较复杂罢了。

2. Animation库

讲解这一部分,也考虑过将Flutter的动画原理先介绍一下。想了想,前一篇文章介绍过这些普世的动画原理,Flutter只不过是特定平台的实现,无非是实现手段的不同,因此,Flutter动画原理的解析,放到本文最后的小节部分,在代码的基础上去解释,笔者觉得更加好理解。

2.1 animation.dart

animation.dart定义了动画的四种状态,以及核心的抽象类Animation。

2.1.1 动画的四种状态

这个文件中定义了Animation的四种状态:

  • dismissed:动画的初始状态
  • forward:从头到尾播放动画
  • reverse:从尾到头播放动画
  • completed:动画完成的状态

2.1.2 Animation类

Animation类是Flutter动画中核心的抽象类,它包含动画的当前值和状态两个属性。定义了动画的一系列回调,

  • 动画过程中值变化的回调:
void addListener(VoidCallback listener);
void removeListener(VoidCallback listener);
  • 状态的回调函数:
void addStatusListener(AnimationStatusListener listener);
void removeStatusListener(AnimationStatusListener listener);

2.2 curve.dart

A curve must map t=0.0 to 0.0 and t=1.0 to 1.0.

看到这段英文,首先会想到什么?没错,插值器。Curve也是一个抽象类,定义了时间与数值的一个接口。

double transform(double t);

例如一个线性的插值器,实现代码如下。

class _Linear extends Curve {
const _Linear._(); @override
double transform(double t) => t;
}

该文件下面定义了非常多类型的插值器,具体的实现不一一展开了。Flutter定义了一系列的插值器,封装在Curves类中,有下面13种效果。

  • linear
  • decelerate
  • ease
  • easeIn
  • easeOut
  • easeInOut
  • fastOutSlowIn
  • bounceIn
  • bounceOut
  • bounceInOut
  • elasticIn
  • elasticOut
  • elasticInOut

如果上面的13种还不满足需求的话,还可以使用Cubic类来进行自定义的构造。可以看出这块儿实现参考了web中的相关实现。

2.3 tween.dart

该文件定义了一系列的估值器,Flutter通过抽象类Animatable来实现估值器。关于Animatable,我们可以先看下其定义。

An object that can produce a value of type T given an [Animation] as input.

可以根据不同的输入,产出不同的数值。通过重载下面的函数来产生不同的估值器。

T transform(double t);

它的最主要的子类是Tween,一个线性的估值器,实现如下,非常的简单,就是一个线性函数。

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的基础上实现了不同类型的估值器。

  • ReverseTween
  • ColorTween
  • SizeTween
  • RectTween
  • IntTween
  • StepTween
  • ConstantTween

还可以通过自定义的插值器去实现估值器,例如通过curve实现的估值器CurveTween。

2.4 animation_controller.dart

动画的控制,就在这个文件下面实现,其中最重要的部分是AnimationController,它派生自Animation类。

AnimationController的功能有如下几种:

  • 播放一个动画(forwaed或者reverse),或者停止一个动画;
  • 设置动画的值;
  • 设置动画的边界值;
  • 创建基于物理的动画效果。

默认情况下,AnimationController是线性的产生0.0到1.0之间的值,每刷新一帧就产出一个数值。AnimationController在不使用的时候需要dispose,否则会造成资源的泄漏。

2.4.1 TickerProvider

提到AnimationController必须要先说一下TickerProvider。

An interface implemented by classes that can vend Ticker objects.

TickerProvider定义了可以发送Ticker对象的接口,

Ticker createTicker(TickerCallback onTick);

Ticker能干什么呢?

Tickers can be used by any object that wants to be notified whenever a frame triggers.

它的主要作用是获取每一帧刷新的通知,作用就显而易见了,相当于给动画添加了一个动起来的引擎。

2.4.2 AnimationController

现在再次回到AnimationController。上面为什么要先说一下TickerProvider呢,这是因为AnimationController的构造函数中需要一个TickerProvider参数。

结合上面介绍的插值器、估值器以及Ticker回调,AnimationController大致的工作流程,我相信很多人都可以理出来了。

随着时间的流逝,插值器根据时间产生的值作为输入,提供给估值器,产生动画的实际效果值,结合Ticker的回调,渲染出当前动画值的图像。这也是补间动画的工作原理。

AnimationController具体的源码不做分析了,可以看到Flutter的动画实现的其实是相当的原始,AnimationController需要一个触发刷新的回调,输出也是值的改变,并不像成熟平台里面的配合View去做动画。

3. Physics库

Physics库基本上就是插值器的实现部分,这部分比较简单

Simulation定义了基于物理动画的相关接口,具体有位置、速度、是否完成以及公差(Tolerance)

double x(double time);
double dx(double time);

GravitySimulation的实现如下,其中_a加速度,_x是初始距离,_v是初始速度:

@override
double x(double time) => _x + _v * time + 0.5 * _a * time * time; @override
double dx(double time) => _v + time * _a;

相信学过高中物理的读者,对这公式不会陌生。其他几种具体实现不在此处一一展开了哈。如果扩展这个物理动画库的话,也很好去扩展,掌握一些物理公式,就可以去仿照实现了。

4. Ticker

关于动画的驱动,在此简单的说一下,Ticker是被SchedulerBinding所驱动。SchedulerBinding则是监听着Window.onBeginFrame回调。

Window.onBeginFrame的作用是什么呢,是告诉应用该提供一个scene了,它是被硬件的VSync信号所驱动的。

具体可以查看sky_engine下面的window.dart的实现,不做展开了。

5. 小节

本篇文章简单的从代码的层面解析了一下Flutter的动画,更深入的Ticker这块儿,感兴趣的读者可以自行去了解,这块儿涉及到sky_engine下面的代码。

本篇文章,笔者依然试图绕过代码去讲解一些普适性的东西,但是Flutter这块儿代码实现的确实挺简单的,造成的问题是调用起来费劲。

基于物理的动画,我们要知道深层次的是物理公式,有这个基础,我们才可以制作出符合感官的动画效果。其本质也是补间动画,过程可以被计算出来。

可以说的宽泛一些,一般的动画,大部分都是补间动画,如果我们自行去设计一套动画系统,插值器、估值器、驱动部分以及动画的管理部分,这四个模块之间相互协调输出一帧一帧的动画过场。绝大部分平台的动画设计,也都逃不过这些因素,只不过实现的方式各不相同。

如果文中有错误的地方,烦请指正,笔者水平有限,再次感谢。

转:Flutter动画二的更多相关文章

  1. F#之旅8 - 图片处理应用之动画二维码

    首先,先介绍下什么是动画二维码.前些天在网上闲逛,突然看到一个开源项目,发现一种二维码的新玩法.https://github.com/sylnsfar/qrcode/blob/master/READM ...

  2. 转:Flutter动画一

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

  3. Flutter 动画详解(一)

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

  4. XamarinAndroid组件教程设置自定义子元素动画(二)

    XamarinAndroid组件教程设置自定义子元素动画(二) (9)打开MainActivity.cs文件,为RecylerView的子元素设置添加和删除时的透明动画效果.代码如下: …… usin ...

  5. jquery实现一些小动画二

    jquery实现一些小动画二 jquery实现拖拽功能 <!DOCTYPE html> <html lang="en"> <head> < ...

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

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

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

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

  8. Flutter 38: 图解 Flutter 基本动画 (二)

    小菜前两天学习了以下 Animation 的基本动画,接下来小菜学习以下稍微进阶版的 Animation 动画. 复合动画 小菜前两天学习的主要是基本的单一动画,当然多个动画效果集一身也是毫无问题的, ...

  9. Flutter 动画鼻祖之CustomPaint

    老孟导读:CustomPaint可以称之为动画鼻祖,它可以实现任何酷炫的动画和效果.CustomPaint本身没有动画属性,仅仅是绘制属性,一般情况下,CustomPaint会和动画控制配合使用,达到 ...

随机推荐

  1. IOC,DIP,DI,IoC容器

    定义 IOC(Inversion of Control  控制反转),DIP(Dependency Inverson Principle 依懒倒置)都属于设计程序时指导原则,并没有具体的实现.比较常用 ...

  2. 配置多个 git 账号的 ssh密钥

    背景 在工作中,我们通常会以 ssh 的方式配置公司的 git 账号,但是平时也会使用 github 管理自己的项目.因此,我们需要为自己的 github 创建一个新的 git 账号,这就需要生成新的 ...

  3. Java集合类:"随机访问" 的RandomAccess接口

    引出RandomAccess接口 如果我们用Java做开发的话,最常用的容器之一就是List集合了,而List集合中用的较多的就是ArrayList 和 LinkedList 两个类,这两者也常被用来 ...

  4. 结合JDK源码看设计模式——建造者模式

    概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...

  5. Linux系统启动详解

    系统启动流程 通过下图认识下Linux系统的总体启动流程. BIOS BIOS一般负责检查硬件和查找启动设备. MBR:Boot Code MBR只是一段引导代码,真正的引导是由引导程序去执行的. G ...

  6. HTML和CSS前端教程03-CSS文本样式

    目录 1.CSS颜色-建议就用十六进制 2.CSS长度的度量单位-建议就用px 3.CSS文本样式 3.1. 字体属性 3.1. 文本样式 1.CSS颜色-建议就用十六进制 p{ color: #ff ...

  7. dns server 域名解析总结

    1.客户有两种使用公网域名解析的方法,一种是,直接配置A记录,将域名直接解析到ip地址.第二种是,配置NS记录,将对这个域名的解析分配给另外一个域名服务器,这个域名服务器就是客户自己搭建的内部域名服务 ...

  8. Andriod Studio安装教程

    最近开设安卓课程,无奈于开发团队不再更新eclipse上sdk兼容问题,在eclipse上浪费了两天时间,换了Andriod Studio, Andriod Studio下载网址:http://www ...

  9. gitbook 入门教程之发布电子书

    输出目标文件 语法格式: gitbook build [book] [output] 默认情况下,gitbook 输出方式是静态网站,其实 gitbook 的输出方式有三种: website, jso ...

  10. ASP.NET Core 入门教程 6、ASP.NET Core MVC 视图布局入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)视图母版页教程 ASP.NET Core MVC (Razor)带有Section的视图母版页教程 ASP.NET Cor ...