手把手教你用Flutter做炫酷动画
导读:随着技术的发展,很多网页开发技术都带有动画效果,比如淡入淡出、渐变、变大变小,等等。Flutter中的动画效果可以用酷炫来形容,这也是Flutter的一大特色。现代的应用程序不仅仅需要程序稳定、好用,还需要好看,体验好。那么动画效果是必不可少的。
作者:亢少军
来源:大数据DT(ID:bigdatadt)
01 动画概念
动画顾名思义,就是动起来的画面。如果一直持续的动再加上音频那就是我们平时看的电影了。那么画面为什么会动起来了呢?在回答这个问题之前,我们先引入一个概念。
人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留的视觉称“后像”,视觉的这一现象则被称为“视觉暂留”。
视觉暂留被认为是电影的最重要的一个理论基础。我们看到的动画,实际上是一连串的画面组成,只不过是以很快的速度去播放,人眼在下一个画面出来之前,还残留着上一个画面的视觉,看起来就像是在没有间隔的播放这一系列的图片,也就是我们称之为的动画。
1. 帧与FPS
帧就是影像动画中最小单位的单幅影像画面,一帧就是一副静止的画面。比如我们看到的电影胶片中的每一格即为一帧,电影通常为24帧。
帧又分为关键帧和过渡帧,如下所示:
关键帧:相当于二维动画中的原画,指角色或者物体运动或变化中的关键动作所处的那一帧。
过渡帧:关键帧与关键帧之间的动画可以由软件来创建,叫做过渡帧或者中间帧。
FPS(Frame Per Second),即每秒显示帧的数量。电影每秒播放24帧,即帧率为24FPS。帧率越大则显示的画面越流畅,动画及视频是同一个原理。
2. 插值器/估值器
为了使得动画呈现出丰富的动画效果,就需要使用非线性动画,插值器与估值器可以解决这个问题。概念如下所示:
插值器:设置属性值从初始值过渡到结束值的变化规律,如匀速、加速及减速等等。即确定了动画效果变化的模式,如匀速变化、加速变化等等。主要应用于实现非线性运动的动画效果。
估值器:设置属性值从初始值过渡到结束值的变化具体数值。估值器的作用是协助插值器实现非线性运动的动画效果。
插值器决定值的变化规律(匀速、加速),即决定的是变化趋势,而接下来的具体变化数值则交给估值器。
如:动画进行了50%(初始值=100,结束值=200 ),那么匀速插值器计算出了当前属性值改变的百分比是50%,那么估值器则负责计算当前属性值 = 100 + (200-100)x50% = 150。
插值器其实并不复杂,就是一个数学函数,设置属性值从初始值过渡到结束值的变化规律。每个平台都有自己定义好的一系列插值器,可以供开发者选择使用,也提供自定义的接口,本质上是一个贝塞尔函数。
3. Flutter中的动画类型
Flutter中动画分为两类,如下所示:
补间(Tween)动画:定义开始点、结束点、时间和速度等参数,然后由框架自动计算如何从开始点过度达到结束点。
基于物理的动画:模拟真实世界的行为。例如,当你掷球时,球在何处落地,取决于抛球速度有多快、球有多重、距离地面有多远。
02 Flutter的动画相关类
首先来看下Flutter的动画基础概念和相关类,如下所示:
Animation:Flutter中动画的核心类
AnimationController:动画管理类
CurvedAnimation:用于定义非线性曲线动画
Tween:补间对象,用于计算动画使用的数据范围之间的插值。
Listeners和StatusListeners:用于监听动画状态改变
1. Animation介绍
Flutter中的动画核心类,我们可以理解为Animation是Flutter中动画的基类。它是个抽象类(abstract),所以不能够直接创建其对象来使用动画。Animation具有以下特性:
Animation对象知道动画的当前状态(例如,它是开始、停止还是向前或向后移动),但它不知道屏幕上显示的内容。
Flutter中的Animation对象是一个在一段时间内依次生成一个区间之间值的类。Animation对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。根据Animation对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。
Animation还可以生成除double之外的其他类型值,如:Animation<Color> 或 Animation<Size>。
Animation对象有状态,可以通过访问其value属性获取动画的当前值。
Animation对象本身和UI渲染没有任何关系。
2. AnimationController动画管理类
AnimationController是一个特殊的Animation对象。其继承自Animation ,因此可以在需要Animation对象的任何地方使用它。默认情况下,AnimationController在给定的持续时间内线性生成从0.0到1.0的值。AnimationController在不使用的时候需要dispose,否则会造成资源的泄漏。AnimationController对象创建如下所示:
AnimationController controller = AnimationController(duration: const Duration(milliseconds: 2000),vsync: this);
上述是AnimationController 对象的创建方式,构造函数第一个参数是动画执行的时间,单位是毫秒。第二个vsync传入是防止动画离屏之后继续消耗资源。
vsync对象会绑定动画的定时器到一个可视的Widget,所以当Widget不显示时,动画定时器将会暂停,当Widget再次显示时,动画定时器重新恢复执行,这样就可以避免动画相关UI不在当前屏幕时消耗资源。如果要使用自定义的State对象作为vsync时,请包含TickerProviderStateMixin,代码结构大致如下所示:
class MyApp extends StatefulWidget {_AnimationApp createState() => _AnimationApp();
}class _AnimationApp extends State<MyApp> with SingleTickerProviderStateMixin {//动画实现
}
这里需要提一下TickerProvider类,它的主要作用是获取每一帧刷新的通知,作用相当于给动画添加了一个动起来的引擎。
AnimationController 提供了几个常用的方法。
<!--开始动画,从开始值向结束值-->
TickerFuture forward({ double from }) {}<!--开始反向运行此动画-->
TickerFuture reverse({ double from }) {}<!--开始执行动画,结束后重新启动-->
TickerFuture repeat({ double min, double max, Duration period }) {}<!--使用阻尼效果驱动动画-->
TickerFuture fling({ double velocity: 1.0 }) {}<!--停止动画-->
void stop({ bool canceled: true }) {}<!--释放此对象使用的资源,此方法调用后不再控制器对象不再可用-->
void dispose() {}
3. CurvedAnimation非线性动画
CurvedAnimation继承Animation,它将动画过程定义为一个非线性曲线,属于Animation<double>类型。构建其对象的方式如下所示:
CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
构造函数中传入控制器和要执行的曲线方式。Curves类定义了许多常用的曲线,也可以创建自己的,例如我们使用数学函数Math.sin方法构建一个抖动的曲线,代码如下所示:
class ShakeCurve extends Curve {@overridedouble transform(double t) {return math.sin(t * math.PI * 2);}
}
Flutter定义了一系列的插值器,封装在Curves类中,有下面13种效果:
linear
decelerate
ease
easeIn
easeOut
easeInOut
fastOutSlowIn
bounceIn
bounceOut
bounceInOut
elasticIn
elasticOut
elasticInOut
4. Tween补间值生成类
AnimationController对象的范围为0.0到1.0。如果需要不同的范围或不同的数据类型,可以使用Tween将动画配置为插入到不同的范围或数据类型。例如,以下Tween从0.0变为500.0:
Tween doubleTween = Tween<double>(begin: 0.0, end: 500.0);
构造函数传入只需要传入begin和end两个值,当然这里不一定只是double值。
Tween继承自Animatable<T>,而不是继承自Animation<T>。Animatable与Animation相似,不是必须输出double值。例如,ColorTween指定两种颜色之间的过渡。
final Tween colorTween =
ColorTween(begin: Colors.transparent, end: Colors.black54);
要使用Tween对象,请调用其animate()方法,传入一个控制器对象。例如,以下代码在100毫秒内生成从0到200的整数值。
final AnimationController controller = AnimationController(duration: const Duration(milliseconds: 100), vsync: this);
Animation<int> alpha = IntTween(begin: 0, end: 200).animate(controller);
注意:animate()返回的是一个Animation,而不是一个Animatable。
Flutter通过抽象类Animatable来实现估值器。Animatable可以根据不同的输入,产出不同的数值。通过重载下面的函数来产生不同的估值器。
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
5. Listeners和StatusListeners动画监听
Animation对象可以有Listeners和StatusListeners,用addListener来进行动画监听和addStatusListener进行动画状态添加监听。只要动画的值发生变化,就会调用监听器。我们通常可用调用setState以将动画重置状态。动画开始,结束,前进或后退时调用StatusListener,下列是Flutter提供动画的监听方法。
<!--动画添加监听-->
void addListener(VoidCallback listener);<!--动画移除监听-->
void removeListener(VoidCallback listener);<!--动画状态添加监听-->
void addStatusListener(AnimationStatusListener listener);<!--动画状态移除监听-->
void removeStatusListener(AnimationStatusListener listener);
动画状态如下:
<!--动画状态-->
enum AnimationStatus {<!--动画在开始时停止--> dismissed,<!--动画从开始状态执行到结束状态-->forward,<!--动画反向执行,从结束状态执行到开始状态-->reverse,<!--动画执行完成-->completed,}
6. 动画控制流程
当我们理解了插值器(Curve)、估值器(Tween)以及Ticker回调的原理。我们就可以理出AnimationController大致的工作流程。
随着时间的流逝,插值器根据时间产生的值作为输入,提供给估值器,产生动画的实际效果值,结合Ticker的回调,渲染出当前动画值的图像。这也是补间动画的工作原理。如下图所示。
▲动画控制流程图
关于作者:亢少军,资深开发者,创业者。专注于视频通讯技术领域。国内首本Flutter著作《Flutter技术入门与实战》作者。多年从事视频会议、远程教育等技术研发,对于Android、iOS以及跨平台开发技术有比较深入的研究和应用,作为主要程序员开发了多个应用项目,涉及医疗、交通、银行等领域。
延伸阅读《Flutter技术入门与实战》第2版
点击上图了解及购买
转载请联系微信:DoctorData
推荐语:本书是多位人工智能技术专家和大数据技术专家多年工作经验的结晶,从工具使用、技术原理、算法设计、案例实现等多个维度对深度学习进行了系统的讲解。内容选择上,广泛涉猎、重点突出、注重实战;内容安排上,实例切入、由浅入深、循序渐进;表达形式上,深度抽象、化繁为简、用图说话。
图书同步配套视频:
https://flutter.ke.qq.com
Flutter开源项目请关注:
https://github.com/kangshaojun
Flutter交流学习群:894109159
作者QQ:283796665
微信:kangshaojun888
「大数据」内容合伙人之「鉴书小分队」上线啦!
最近,你都在读什么书?有哪些心得体会想要跟大家分享?
数据叔最近搞了个大事——联合优质图书出版商机械工业出版社华章公司发起鉴书活动。
简单说就是:你可以免费读新书,你可以免费读新书的同时,顺手码一篇读书笔记就行。详情请在大数据公众号后台对话框回复合伙人查看。
有话要说????
Q: Flutter还有哪些炫酷应用?
欢迎留言与大家分享
猜你想看????
推给我的广告都跟我最近看的内容有关系,怎么做到的?
很火的深度学习框架PyTorch怎么用?手把手带你安装配置
天猫双11、12306怎样扛住流量高峰“集中轰炸”?一文全揭秘!
87万人已开通5G套餐!8本书,给你剧透未来科技
更多精彩????
在公众号对话框输入以下关键词
查看更多优质内容!
PPT | 报告 | 读书 | 书单 | 干货
大数据 | 揭秘 | Python | 可视化
AI | 人工智能 | 5G | 中台
机器学习 | 深度学习 | 神经网络
合伙人 | 1024 | 段子 | 数学
据统计,99%的大咖都完成了这个神操作
????
觉得不错,请把这篇文章分享给你的朋友
转载 / 投稿请联系:baiyu@hzbook.com
更多精彩,请在后台点击“历史文章”查看
点击阅读原文,了解更多
手把手教你用Flutter做炫酷动画相关推荐
- 从零开始搭建自己的个人博客 ---> 手把手教你搭建自己的炫酷博客
演示地址:https://lilli_jingjing.gitee.io/blog/ 效果图: 1.准备一台可以联网的电脑[我以机房电脑为例] 2.下载nodeJs[我们去下载12版本的,高版本会伴随 ...
- 怎么将自己的头像p到特定的背景图_【后期修图】photoshop手把手教你制作属于自己的酷炫的微信头像...
原标题:[后期修图]photoshop手把手教你制作属于自己的酷炫的微信头像 效果图先放上 1.新建一个白色的背景,这里是1080*720的.然后在图层面板下面单击创建新的调整图层/渐变,设 置 好渐 ...
- 超详细——手把手教你用threejs实现一个酷炫的模型发光扫描效果(三)
上一篇文章 voidjay,公众号:web前端可视化超详细--手把手教你用threejs实现一个酷炫的模型发光扫描效果(二) 上一篇文章已完成基本效果的实现,本文则完成整个项目的灵魂:发光效果以及模型 ...
- html5自动换图,html5教你做炫酷的碎片式图片切换 (canvas)
前言 老规矩,先上源码.图片区域是可以点击的,动画会从点击的位置开始发生. 本来这个效果是我3年前做的,只是当是是用无数个 div 标签完成的,性能比较成问题,在移动端完全跑不动.最近心血来潮想学习一 ...
- 【手把手教你用Matlab做双目摄像头标定】Ubuntu环境
[手把手教你用Matlab做双目摄像头标定] Ubuntu20.04环境 准备工作 你需要一个标定板 你需要一个双目摄像头 获取双目摄像头的设备号 跑起来看看 分割图像并完成拍照 使用Matlab进行 ...
- python代码示例图形-纯干货:手把手教你用Python做数据可视化(附代码)
原标题:纯干货:手把手教你用Python做数据可视化(附代码) 导读:制作提供信息的可视化(有时称为绘图)是数据分析中的最重要任务之一.可视化可能是探索过程的一部分,例如,帮助识别异常值或所需的数据转 ...
- 手把手教你用C#做疫情传播仿真
手把手教你用C#做疫情传播仿真 在上篇文章中,我介绍了用 C#做的疫情传播仿真程序的使用和配置,演示了其运行效果,但没有着重讲其中的代码. 今天我将抽丝剥茧,手把手分析程序的架构,以及妙趣横生的细节. ...
- python画图代码大全-纯干货:手把手教你用Python做数据可视化(附代码)
原标题:纯干货:手把手教你用Python做数据可视化(附代码) 导读:制作提供信息的可视化(有时称为绘图)是数据分析中的最重要任务之一.可视化可能是探索过程的一部分,例如,帮助识别异常值或所需的数据转 ...
- 举个栗子!Tableau 技巧(138):学做炫酷的温度计图表
来自北京的气象分析师提了一个需求:我经常分析温度数据,Tableau 可否实现像温度计那样的图表? 图片来自网络 当然,温度计图表在 Tableau 中可以实现!并且,它不仅可以用来呈现温度数据,还适 ...
最新文章
- Atitit.提升 升级类库框架后的api代码兼容性设计指南
- 内核与ramdisk到底是什么关系?
- 节点服务器虚拟网络,虚拟网络功能节点放置研究
- 千元显卡玩转百亿大模型,清华推出工具包BMInf让模型推理轻而易举
- hbase数据导入到mysql(转载+自己验证整理,目前失败)
- docker 日志_解决docker容器日志导致主机磁盘空间满了的情况
- Delphi窗体显示Echarts图表
- 由一道题目引发的为稳定与不稳定的排序思路
- matlab中心化样本矩阵,第二讲实验.doc
- 使用delphi 开发多层应用(十四)使用Basic4android 显示kbmMW server数据
- 获取Map集合中数据的方法
- 【opencv4】——fatal error: opencv2/opencv.hpp: No such file or directory #include <opencv2/opencv.hpp>
- 解决extremeComponents中文按拼音排序问题
- 各种浏览器下的页面元素xpath获取方法
- 深度分析《英雄联盟》游戏运营商背后的大数据支撑体系
- 机器学习笔记 - 学习使用TensorFlow和张量处理单元 (TPU) 构建图像分类模型
- NLP入门从入门到实战 实体命名识别 +中文预处理之繁简体转换及获取拼音
- 百度2014校园招聘-研发工程师笔试题(济南站)
- 快速解绑微信公众号管理员
- LR2021下载LR2021最新10.1.0下载安装Lightroom最新下载1分钟看完就能自己操作
热门文章
- C++ | Qt 获取局域网中存在的主机(IP以及主机名)
- 软件设计师冲刺笔记(一)
- C/C++使用Select检索MySQL中的数据
- ERRORS:*: (auth.E003) ‘User.username‘ must be unique because it is named as the ‘USERNAME_FIELD
- 计算机进位法,计算机基础知识--进位计数制.docx
- 为什么html运行之后不滚动,为什么很多移动端的HTML UI,在滚动时都用transform属性而不是用传统的滚动条?...
- win7系统修复工具_205个电脑系统修复小工具, 联想工程师专用!
- (数据库系统概论|王珊)第一章绪论-第一节:数据库系统概论
- Origin使用手册/笔记第一部分:工作表行列操作
- windbg 常用查看锁以及互斥量