Flutter动画(一)Ticker、Animate 原理

在任何系统的UI框架中,动画原理都是类似的,即:在一段时间内,快速地多次改变UI外观;由于人眼会产生视觉暂留,所以最终看到的就是一个“连续”的动画。

Flutter中对动画进行了抽象,主要涉及 Animation、Curve、Controller、Tween这四个角色,它们一起配合来完成一个完整动画。

1.基本概念

1. Animation

Animation是一个抽象类,它本身和UI渲染没有任何关系,而它主要的功能是保存动画的插值和状态。Animation对象是一个在一段时间内依次生成一个区间(Tween)之间值的类。Animation对象在整个动画执行过程中输出的值可以是线性的、曲线的、一个步进函数或者任何其他曲线函数等等,这由Curve来决定。

我们可以通过Animation来监听动画每一帧以及执行状态的变化Animation有如下两个方法:

  1. addListener();它可以用于给Animation添加帧监听器,在每一帧都会被调用。帧监听器中最常见的行为是改变状态后调用setState()来触发UI重建。
  2. addStatusListener();它可以给Animation添加“动画状态改变”监听器;动画开始、结束、正向或反向(见AnimationStatus定义)时会调用状态改变的监听器。

2. Curve

动画过程可以是匀速的、匀加速的或者先加速后减速等。Flutter中通过Curve(曲线)来描述动画过程,我们把匀速动画称为线性的(Curves.linear),而非匀速动画称为非线性的。

要使用非匀速动画,我们可以通过CurvedAnimation来指定动画的曲线,如:

final CurvedAnimation curve =CurvedAnimation(parent: controller, curve: Curves.easeIn);

Curve的关键是实现一个transform方法,就是

 transform(double t) → double 

t是时间点,取值是0到1之间。返回值是动画的进展,取值也是0到1之间。

3. AnimationController

AnimationController派生自Animation<double>,因此可以在需要Animation对象的任何地方使用。 但是,AnimationController具有控制动画的其他方法,包含动画的启动forward()、停止stop() 、反向播放 reverse()等方法。AnimationController可以在一段时间里生成一个区间(默认是0.0到1.0)中的值:

final AnimationController controller = AnimationController( duration: const Duration(milliseconds: 2000), lowerBound: 10.0,upperBound: 20.0,vsync: this
);

4. Tween

默认情况下,AnimationController对象值的范围是[0.0,1.0]。如果我们需要构建UI的动画值在不同的范围或不同的数据类型,则可以使用Tween来添加映射以生成不同的范围或数据类型的值。例如:

final Tween colorTween =ColorTween(begin: Colors.transparent, end: Colors.black54);

Tween继承自Animatable<T>,而不是继承自Animation<T>Animatable中主要定义动画值的映射规则。

Tween对象不存储任何状态,相反,它提供了evaluate(Animation<double> animation)方法,它可以获取动画当前映射值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其他处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态。

要使用 Tween 对象,需要调用其animate()方法,然后传入一个控制器对象。例如,以下代码在 500 毫秒内生成从 0 到 255 的整数值。

final AnimationController controller = AnimationController(duration: const Duration(milliseconds: 500), vsync: this,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);

5.CurveTween

CurveTween有别于Tween的是,它不能指定动画值的上下限,它的作用是根据指定的Curve来转换animation的值。Tween可以通过chain来组合CurveTween,实现指定区间的动画曲线。

6.CurvedAnimation

CurvedAnimation是将动画曲线应用到已有Animation,来生成一个新的Animation。

简单论述下几者的关系:animated之间可以chain;animated可以对已有animation进行animate来生成新的animation,animation可以drive animated来生成animation;controller是一个完备的animation,可以直接使用,除非数值区间或者动画曲线不符合要求。基于以上论述,以下代码是等效的:

//1
final Animation<double> cAnimation1 = CurvedAnimation(parent: controller,curve: Curves.ease,
);
final Animation<double> animation = Tween(beigin:0.0, end:2.0).animate(cAnimation1)//2
final Animation<double> animation = Tween(beigin:0.0, end:2.0).chain(CurveTween(curve: Curves.ease)).animate(controller)//3
final Animation<double> cAnimation2 = controller.drive(CurveTween(curve: Curves.ease),
);
final Animation<double> animation = Tween(beigin:0.0, end:2.0).animate(cAnimation2)

2.实现细节

1.vsync:this

我们看到前面AnimationController构造函数里,有个vsync参数,我们把this传了进去,而且我们还在this所指向的state混入了SingleTickerProviderStateMixin。我们来看看实现源码:

vsync 对象创建了一个 _ticker ,而传入的 _tick 是一个回调函数。查看源码它是用于更新 value ,也就是说 AnimationController.value 是在此回调中发生改变。

我们将视角回调 _ticker = vsync.createTicker(_tick); 来看看 Ticker

2.Ticker

class Ticker {TickerFuture? _future;bool get muted => _muted;bool _muted = false;set muted(bool value) {if (value == muted)return;_muted = value;if (value) {unscheduleTick();} else if (shouldScheduleTick) {scheduleTick();}}bool get isTicking {if (_future == null)return false;if (muted)return false;if (SchedulerBinding.instance!.framesEnabled)return true;if (SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.idle)return true; // for example, we might be in a warm-up frame or forced framereturn false;}@protectedbool get shouldScheduleTick => !muted && isActive && !scheduled;void _tick(Duration timeStamp) {assert(isTicking);assert(scheduled);_animationId = null;_startTime ??= timeStamp;_onTick(timeStamp - _startTime!);if (shouldScheduleTick)scheduleTick(rescheduling: true);}@protectedvoid scheduleTick({ bool rescheduling = false }) {assert(!scheduled);assert(shouldScheduleTick);_animationId = SchedulerBinding.instance!.scheduleFrameCallback(_tick, rescheduling: rescheduling);}@protectedvoid unscheduleTick() {if (scheduled) {SchedulerBinding.instance!.cancelFrameCallbackWithId(_animationId!);_animationId = null;}assert(!shouldScheduleTick);}@mustCallSupervoid dispose() {if (_future != null) {final TickerFuture localFuture = _future!;_future = null;assert(!isActive);unscheduleTick();localFuture._cancel(this);}}
}

TickerSchedulerBinding 驱动。flutter 每绘制一帧就会回调 Ticker._onTick(),所以每绘制一帧 AnimationController.value 就会发生变化。

接下来看一下 Ticker 其他成员与方法:

  • muted : 设置为 ture 时钟仍然可以运行,但不会调用该回调。
  • isTicking: 是否可以在下一帧调用其回调,如设备的屏幕已关闭,则返回false。
  • _tick(): 时间相关的计算交给 _onTick(),受到 muted 影响。
  • scheduleTick(): 将 _tick() 回调交给 SchedulerBinding 管理,flutter 每绘制一帧都会调用它。
  • unscheduleTick(): 取消回调的监听。

_onTick在AnimationController中实现:

这里主要更新value、status以及notifyListeners。对于renderObject,调用notifyListeners会调用markNeedsPaint方法,在下一帧进行重绘。

把_onTick传入创建Ticker的方法:

3.SingleTickerProviderStateMixin

@optionalTypeArgs
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {Ticker? _ticker;@overrideTicker createTicker(TickerCallback onTick) {_ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null)return _ticker!;}@overridevoid dispose() {super.dispose();}@overridevoid didChangeDependencies() {if (_ticker != null)_ticker!.muted = !TickerMode.of(context);super.didChangeDependencies();}}

SingleTickerProviderStateMixin 就是我们在 Statevsync:this ,它做了一个桥梁连接了 StateTicker

以上源码重要一点:是在 didChangeDependencies() 中将 muted = !TickerMode.of(context) 初始化一遍。 TickerModeInheritedWidgetwidget 中的属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/764265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

后端前行Vue之路(一):初识Vue

1.Vue是什么 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。另一方…

如何用pytorch调用预训练Swin Transformer中的一个Swin block模块

1&#xff0c;首先&#xff0c;我们需要知道的是&#xff0c;想要调用预训练的Swin Transformer模型&#xff0c;必须要安装pytorch2&#xff0c;因为pytorch1对应的torchvision中不包含Swin Transformer。 2&#xff0c;pytorch2调用预训练模型时&#xff0c;不建议使用pretr…

【python】python3基础

文章目录 一、安装pycharm 二、输入输出输出 print()文件输出&#xff1a;格式化输出&#xff1a; 输入input注释 三、编码规范四、变量保留字变量 五、数据类型数字类型整数浮点数复数 字符串类型布尔类型序列结构序列属性列表list &#xff0c;有序多维列表列表推导式 元组tu…

基于python+vue网络相册设计与实现flask-django-nodejs-php

网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&#xff0…

CentOS/RHEL 6.5 上 NFS mount 挂起kernel bug

我本身有四台机器做WAS集群&#xff0c;挂载nfs&#xff0c;其中随机一台客户端计算机端口关闭释放将进入不良状态&#xff0c;对 NFSv4 挂载的任何访问都将挂起&#xff08;例如“ls&#xff0c;cd 或者df均挂起”&#xff09;。这意味着没有人并且所有需要访问共享的用户进程…

深度学习图像处理02:Tensor数据类型

上一讲深度学习图像处理01&#xff1a;图像的本质&#xff0c;我们了解到图像处理的本质是对矩阵的操作。这一讲&#xff0c;我们讲介绍深度学习图像处理的基本数据类型&#xff1a;Tensor类型。 在深度学习领域&#xff0c;Tensor是一种核心的数据结构&#xff0c;用于表示和…

复旦大学MBA:iLab项目探寻科技创新 助力企业出海

2024年2月底&#xff0c;新一轮复旦MBA iLab商业咨询项目&#xff08;以下简称iLab项目&#xff09;正式拉开序幕。      科创大时代&#xff0c;如何于变局中创新突破、绘就商业“蓝图”&#xff1f;怎样把握ESG投资机遇&#xff0c;创造可持续发展的未来&#xff1f;如何…

图论07-被包围的区域(Java)

7.被包围的区域 题目描述 给你一个 m x n 的矩阵 board &#xff0c;由若干字符 X 和 O &#xff0c;找到所有被 X 围绕的区域&#xff0c;并将这些区域里所有的 O 用 X 填充。 示例 1&#xff1a; 输入&#xff1a;board [["X","X","X",&qu…

2.6、媒体查询(mediaquery)

概述 媒体查询作为响应式设计的核心,在移动设备上应用十分广泛。媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。媒体查询常用于下面两种场景: 针对设备和应用的属性信息(比如显示区域、深浅色、分辨率),设计出相匹配的布局。当屏幕发生动态改变时(比如分屏…

V2X技术与智能传感器的完美融合:提升城市道路安全

在科技不断创新的今天&#xff0c;城市交通领域涌现了大量新技术。有时候我们不仅仅需要独立应用这些新技术来实现交通的变革&#xff0c;更需要将它们巧妙地结合连接起来&#xff0c;以获取更高效更安全的交通环境。本文将探讨V2X技术与智能传感器的结合&#xff0c;如何在城市…

专为智能设备安全打造 | 基于ACM32 MCU的智能断路器方案

随着我国电网建设的快速发展&#xff0c;数字化变电站成为建设和研究的热点&#xff0c;数字化变电站的核心在于一次设备的智能化与二次设备的网络化&#xff0c;对于断路器这种极其重要的电力一次设备而言&#xff0c;其智能化的实现有十分重要的意义&#xff0c;断路器智能化…

平衡隐私与效率,Partisia Blockchain 解锁数字安全新时代

原文&#xff1a;https://cointelegraph.com/news/exploring-multiparty-computations-role-in-the-future-of-blockchain-privacy&#xff1b; https://medium.com/partisia-blockchain/unlocking-tomorrow-outlook-for-mpc-in-2024-and-beyond-cb170e3ec567 编译&#xff1…

skywalking监听apisix

一、原理 Skywalking结合OpenTelemetry Collector Apisix的promethus插件实现对apisix metrics数据的收集。 二、数据流图 1. Apisix Promethus插件从Apisix收集指标数据。 2. OpenTelemetry Collector通过promethus receiver获取来自Apisix Promethus插件的指标数据&#…

python的OA公文发文管理系统flask-django-php-nodejs

采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”的思想&#xff0c;在OA公文发文管理系统实现了用户、公文分类、公文信息、待办提醒等的功能性。系统根据现有的管理模块进行开发和扩展&a…

(附源码)基于Spring Boot和Vue的前后端分离考研资料分享平台的设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2024年Java精品实战案例《100套》 &#x1f345;文末获取源码联系&#x1f345; &#x1f31…

旅游网站|基于JSP技术+ Mysql+Java+ B/S结构的旅游网站设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

「媒体宣传」企业活动发布会邀请媒体报道的好处与优势?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 企业活动发布会邀请媒体报道具有多种好处与优势&#xff0c;这些都有助于提升企业的知名度、形象和影响力。以下是一些主要的好处与优势&#xff1a; 提升品牌知名度&#xff1a;媒体报道…

目标控制器数字孪生系统的研究与设计

文章来源&#xff1a;铁路计算机应用,2023,32(10):36-41. 作者&#xff1a;许婧&#xff0c;杨硕&#xff0c;季志均 摘要&#xff1a;随着目标控制器&#xff08;OC&#xff0c;Object Controller&#xff09;系统在轨道交通领域的推广应用&#xff0c;其硬件投入较高、研发…

短视频矩阵系统----源头开发

短视频矩阵源码技术开发要求及实现流程&#xff1a; 短视频矩阵开发要求具备视频录制、编辑、剪辑、分享等基本功能&#xff0c;支持实时滤镜、特效、音乐等个性化编辑&#xff0c;能够实现高效的视频渲染和处理。开发流程主要包括需求分析、技术选型、设计架构、编码实现、测试…

OpenHarmony实现一次开发多端部署分布式新闻客户端页面

分布式新闻客户端&#xff08;ArkTS&#xff09; 介绍 本篇Codelab基于栅格布局、设备管理和多端协同&#xff0c;实现一次开发&#xff0c;多端部署的分布式新闻客户端页面。主要包含以下功能&#xff1a; 展示新闻列表以及左右滑动切换新闻Tab。点击新闻展示新闻详情页。点…