5

FlutterComponent最佳实践之动画那些词儿

 2 years ago
source link: https://blog.csdn.net/eclipsexys/article/details/124113701
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

FlutterComponent最佳实践之动画那些词儿

48af8e8e24f8daefe7bcb6f20996a15c.png

点击上方蓝字关注我,知识会给你力量

26cbbe13ad931374053f7a2813a4aa3f.png

什么是动画,从数学上来说,动画指的是一个属性的变换过程,实际上,就是一个函数,将一个属性值变成另一个属性值的过程。

从现实上来说,动画实际上就是将一系列静态的图片,在一定时间内快速切换,从而利用人眼的视觉暂留效应形成动态的画面。

对于现代移动设备来说,保持流畅体验的标准是60帧每秒,即每秒要切换60张静态图,这每一帧,在Flutter中被称之为Tick,也叫Vsync,在使用动画的时候,需要mixin的SingleTickerProviderStateMixin,就是Tick的一种,开发者可以监听Animation的每一帧回调,在回调中去刷新UI,从而实现动画的播放。

在Flutter中,包含两种动画类型,分别是Tween动画和Physics动画。

一个Tween实际上就是定义的属性值的变化区间,而基于Physics的动画,实际上也是一个变化区间,只不过它的变化区间是根据物理引擎计算出来的,更加模拟真实的物理效果。

Physics动画的相关类如下所示。

https://api.flutter.dev/flutter/animation/AnimationController/animateWith.html https://api.flutter.dev/flutter/physics/SpringSimulation-class.html

这两种动画类型,实际上是描述动画的两种方式,一种是通过区间值,另一种是通过模拟物理环境(胡克定律)

首先来思考下,如何来设计一个动画框架——动画,简单来说,就是描述一个属性,将其起始值,经过多长时间,由怎样的变化速率,变成目标值,这样就完成了一次动画。

在Flutter中,上面的这些步骤是如何实现的呢?

  • Tween,负责起始值到目标值的数据生成,可以是0-1,也可以是1-100,也可以是Red-Blue,总之就是数据的变化

  • Curve,负责动画的变化速率,即作用在Tween的中间值上的函数f(x),避免生硬的动画过程

  • AnimationController,负责整个动画的行进过程,即控制动画的开始、结束、循环,以及时长

那么有了这三个核心概念,在Flutter中描述动画就很简单了,通过Tween来描述动画的变化区间,在用AnimationController来管理Tween和Curve,就完成了动画的控制。

不过这里要注意的是,AnimationController是Animation的实现类,所以理论上来说,Flutter Animation的核心应该是Animation、Tween和Curve。

Animation在Flutter中与实际的UI渲染是没有任何关系的,它仅仅是一个数值发生器,和Android中的属性动画ValueAnimator非常类似。

下面,针对前面提到的几个名词来进行下分析,这些东西频繁出现在Flutter动画中,理清它们之间的关系和作用,才能为实现动画打好基础。

Animation与AnimationController

Animation是Flutter中实现动画的核心类,但它更像是一个数值发生器,用于产生指定泛型的数据,或者是根据Tween来生成变换后的区间数值,而整个Widget树,根据数值的更新来重绘,从而产生动画效果。

这也是申明式编程,实现动画更加简单方便的原因,因为它更符合动画的语义效果。

Animation是具有状态的对象,它保存了当前的映射值和当前的运行状态(动画完成、中断)等。所以,当动画Stop后继续播放,这个值是有状态的,它会从Stop的地方继续执行,除非你指定了from: 0。

Animation有两个重要的实现,分别是AnimationController和CurvedAnimation。

  • AnimationController

    AnimationController是Animation的实现,在屏幕刷新的每一帧,AnimationController都会产生一个对应的数值,当不使用Tween时,AnimationController最基础的实现,就是连续的、线性的依次产生一个[0,1]的数值。如果需要改变AnimationController的输出范围,可以通过修改AnimationController的lowerBound、upperBound参数,并在调用时设置controller.forward(from: xxx)函数。

  • CurvedAnimation

    CurvedAnimation也是Animation的实现,只不过它可以根据Curve曲线来生成非线性的区间值。CurvedAnimation并不能驱动动画,它只是一个数值的转换器。

前面提到了AnimationController是一个线性的数值发生器,因为它产生的数值的速率是相同的,但是很多情况下,动画的发生速率是变化的,例如加速或者减速效果,这在Android原生中,是通过Interpolator来实现的,而在Flutter中,可以通过CurvedAnimation来实现。

CurvedAnimation同样继承自Animation,所以它和AnimationController是同等地位的,但是通常情况下,CurvedAnimation的创建是需要AnimationController的。创建一个CurvedAnimation最核心的代码如下所示。

_curvedAnimation = CurvedAnimation(parent: _controller, curve: Curves.bounceIn);

其中parent参数就是需要指定的AnimationController,而curve参数,就是需要指定的插值器,在Curves中,已经内置了很多不同类型的插值器,基本覆盖了常用的使用场景,当然,开发者也可以自定义自己的插值器,只需要继承Curve类并实现transform函数即可。

Tween

Tween,是Animatable的子类,它的作用类似一个函数f(x),它将一个输入x(x的取值范围是[0,1]),经过f的变换,产生新的数值。

那么前面讲解了AnimationController,通过设置AnimationController的一些参数,就可以获得动画的值,那这里为什么还要讲解Tween呢?

Tween与Animation不同,Tween是一个无状态的对象,它只包含begin和end值。当AnimationController默认产生的[0,1]不能满足需求时,就可以通过Tween来生成不同的区间范围值,Tween不保存任何状态,它只是起始值的变换函数。

  • Tween

    Tween不仅仅可以返回double类型的数据,在Flutter SDK中,系统定义了很多内置的Tween,当然,开发者也可以自定义自己的Tween。

  • CurvedTween

    与CurvedAnimation一样,Tween也有类似的CurvedTween

另外,这也是Flutter的一种解耦的方式,AnimationController的职责是产生原始的、统一的[0,1]数值,而具体的动画效果,通过交给相应的Tween-Animation来创建不同的动画类型,将AnimationController中的设置分配到了不同的Tween中,而AnimationController则负责管理这些Tween。

一个最简单的Tween动画,就是将[0,1]变换为[begin,end]。

Tween的类型

Tween有很多不同类型的实现,它们都继承自Animatable,如下图所示。

0ea52d14059cf6f74b1ce600ffd89773.png 2dba725b185c4c96b0ec91d50c06a857

这里通过一个例子来介绍下Tween和ColorTween的使用方法,其它类型的Tween的使用基本类似,可以类推。核心代码如下所示。

Tween的使用非常简单,创建Tween对象并设置相应参数后,通过animate函数关联相应的AnimationController即可(animate函数即将Animatable转换成了Animation)。

可以发现,实际上Tween的使用只是参数上的区别,不同类型的Tween,作用的属性不同,产生的值的类型也不同,这个值可以是具体数字、可以是Color、Offset,甚至是对象。

那么除了通过animate函数以外,还可以通过AnimationController.drive函数来加载一个Tween。从效果上来看AnimationController.drive == Tween.animate,是等效的,其实drive函数本身,也是通过animate来实现的。

Tween与chain

chain函数可以将多个Tween进行复合,一个常用的场景就是与CurveTween复合,给Tween添加插值曲线,这样就不用使用CurvedAnimation来创建Curve动画了,示例代码如下所示。

tween1.chain(CurveTween(curve: Curves.easeIn)).animate(animation)

Tween中叠加chain的原理,实际上就是函数的叠加,因为有时候,一个Tween是很难描述一个复杂的动画的,这个时候,就需要进行叠加了,类似数学中的复合函数g(f(h(x)))。

通过chain,就可以很方便的将复杂动画拆解成多个单一属性的简单动画的叠加,这样就会让动画开发的思路更加清晰。

自定义Tween

Tween表示的是动画的变换函数,Flutter预设了很多种不同的Tween来帮助开发者完成动画的创建,同时也给出了创建自定义Tween的方法,下面的代码就演示了如何创建一个自定义的Tween,来实现打字机的特效。

首先,需要定义一个Tween,用来不断的截取字符串,模拟出文字逐渐出来的效果,代码如下所示。

代码很简单,实际上就是根据动画的进度参数t来对String进行截取。

所以,对Tween的理解不要局限于数值的改变上,任何类型的「改变」,都可以作为Tween。

让我们从Tween的实现上来看下Tween到底是什么东西。

607d5dcb3709fcde0e92a753294e2203.png image-20220409151640729

可以发现,Tween实际上就是一个lerp函数作用之后的数值,也就是说,我们通常使用:

Tween().animate(parent) .value

来获取动画值的方式,本质上和下面这种方式是一样的:

tween.evaluate(_controller)

从源码中,其实也能看出,如下所示。

cf6ad34272122db543615a94cd30945b.png image-20220409152251135

所以,Tween实际上是一个函数,用来告诉系统,begin到end,中间的每一个值的产生是如何进行的。

Curves

在动画的函数中,duration和curve两个非常重要的参数,duration控制的是动画的响应时长,而curve控制的是动画的响应曲线。

duration很好理解,就是动画持续时间,而curve,则是描述动画行进的曲线,默认情况下,动画以线性曲线行进,所以,动画的变换过程是线性的,以恒定不变的速率进行变换,这个过程,在动画中,被称为Interpolator,即插值器,插值器的变换过程,可以用一个函数图像来表示,所以默认的线性变换过程,用图来表示,就如下图所示。

2541e1e3f0c43e1df3d24c98d47e3f45.png 65ee6af49b65fd77ebc2e608b65e0c81

在Flutter中,SDK定义了很多常用的插值器,具体的插值器可以在下面的网站上找到,如下所示。

https://api.flutter.dev/flutter/animation/Curves-class.html

05736949b17aadcd66a5efc2f5c5ba30.png e4adc8dd5e6fa3520a104cc4e786fa14

当一个线性插值器被替换成其它非线性插值器时,动画的行进过程就不是恒定不变的了,而是类似插值器的函数图像来进行变换。

运用插值器,可以让动画的实现过程变的更加符合自然规律、设计规范,让动画更加真实、更加具有美感。

CurvedAnimation是使用Curve的方法之一,另一个方法就是使用CurveTween。这两个方法也是等效的。

我们来看下一个Curve是怎么定义的。

05570aab4acf7bf2a4fb1054d942e34f.png image-20220409150619284

可以发现,其实Curve和动画没有什么直接关系,它的作用就是让原本线性的值,根据某些函数进行转换,从而产生一些不是那么线性的值。

所以,不仅仅是在动画中可以使用Curve,在其它需要的计算场景下,也可以直接使用Curve来进行计算,代码如下所示。

Curves.elasticIn.transform(_controller.value)

上面的这些名词,就是Flutter动画的基石,只有深刻理解这些名词背后的含义,才能对动画的实现了如指掌。

向大家推荐下我的网站 https://xuyisheng.top/  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问

本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。

< END >

作者:徐宜生

更文不易,点个“三连”支持一下👇


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK