Flutter开发进阶之动画

Flutter开发进阶之动画

在Flutter中,动画是至关重要的一个部分,它能够为应用程序提供更加丰富和生动的用户体验,Flutter中的动画系统是UI框架的核心功能之一,也是开发者学习Flutter框架的重要部分,由于动画原理在所有程序中都是相同的,即视觉暂留,因此理解这一原理对于更好地使用Flutter的动画系统至关重要;
动画在应用程序中具有许多用途,例如引导用户注意力、增强视觉效果、提供更好的交互体验等,通过精心设计的动画,应用程序可以变得更加有趣、吸引人,并提高用户的参与度和满意度;
Flutter开发进阶之动画
Flutter开发中动画可以有多种分类,其中可以通过是否模拟现实世界中物理行为物理动画和补间动画。

物理动画

物理动画模拟现实世界中的物理行为,如重力、弹性、摩擦力等;
Flutter的AnimatedPhysics组件提供了这种能力,可以为AnimatedPhysics组件提供一个AccelerationSpec和DecelerationSpec,以定义动画的加速和减速行为。

  Widget build(BuildContext context) {  return AnimatedPhysics(  mass: 100.0,  acceleration: 9.8, // 重力加速度  deceleration: 0.5, // 阻尼系数,决定物体下落后的减速程度  child: Container(  width: 200.0,  height: 200.0,  color: Colors.red,  ),  animationId: _animationId, // 动画ID,用于标识这个动画,用于后续的动画控制操作,例如暂停、恢复等。  );  }  

补间动画

补间动画是更传统的动画方式,它允许你定义动画的开始和结束状态,以及中间过渡状态;
Flutter的AnimatedBuilder和AnimatedCrossFade组件提供了这种能力,还可以通过Tween来构建。

  Widget build(BuildContext context) {  return AnimatedBuilder(  animation: _animationController,  builder: (context, child) {  if (_isFirst) {  return Container(color: Colors.red, child: child);  } else {  return Container(color: Colors.green, child: child);  }  },  child: AnimatedCrossFade(  duration: Duration(seconds: 1),  firstChild: Container(color: Colors.red), // 第一个显示的子组件,初始为红色容器  secondChild: Container(color: Colors.green), // 第二个显示的子组件,初始为绿色容器  crossfadeState: _isFirst ? 1 : 0, // 控制动画状态,true表示第二个子组件显示,false表示第一个子组件显示  firstChildBuilder: (BuildContext context, child, bool visible) { // 可选,用于定制第一个子组件的动画效果,这里我们保持默认行为,不进行定制。  return visible ? child : null;  },  secondChildBuilder: (BuildContext context, child, bool visible) { // 可选,用于定制第二个子组件的动画效果,这里我们保持默认行为,不进行定制。  return visible ? child : null;  },  ),  animationId: _animationController.id, // 动画ID,用于标识这个动画,用于后续的动画控制操作,例如暂停、恢复等。这里我们使用了和之前示例中一样的ID。  );  }  

还可以根据动画的触发方式(隐式和显式)分为隐式动画和显式动画。

隐式动画

隐式动画是Flutter框架自动处理的动画,通常可以使用对应的组件(AnimatedOpacity、AnimatedContainer、AnimatedPadding、AnimatedPositioned、AnimatedSwitcher等)来实现,通过简单的属性设置来实现动画效果,而不需要手动创建和管理动画控制器。

  
Widget build(BuildContext context) {  return Column(  mainAxisAlignment: MainAxisAlignment.center,  children: [  // 示例1:使用AnimatedOpacity创建动画  AnimatedOpacity(  value: _animationValue, // 动画值范围:0.0(完全透明)到1.0(完全不透明)  duration: _controller.duration, // 使用AnimationController的持续时间,确保动画同步。  child: Container(  width: 100,  height: 100,  color: Colors.red,  ),  ),  // 示例2:使用AnimatedContainer创建动画  AnimatedContainer(  duration: _controller.duration, // 使用AnimationController的持续时间,确保动画同步。  curve: Curves.bounceInOut, // 动画曲线  child: Container(  width: 100,  height: 50,  color: Colors.green,  ),  ),  // 其他使用动画效果的子项...  ],  );  
}

显式动画

显式动画是开发者需要手动创建和管理的动画,在Flutter中,这通常通过使用Animated组件(例如AnimatedPositioned,AnimatedBuilder等)以及AnimationController类来完成;
需要明确指定动画的起始状态、结束状态以及过渡的时间和曲线。

class MyAnimatedWidget extends StatefulWidget {    _MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();  
}  class _MyAnimatedWidgetState extends State<MyAnimatedWidget> with SingleTickerProviderStateMixin {  AnimationController _controller;  Tween<double> _tween = Tween<double>(  begin: 0.0,  end: 200.0,  ).animate(_controller);    void initState() {  super.initState();  _controller = AnimationController(  vsync: this,  duration: Duration(seconds: 2), // 动画持续时间  );  }    Widget build(BuildContext context) {  return Column(  mainAxisAlignment: MainAxisAlignment.center,  children: [  AnimatedPositioned(  animation: _controller, // 将动画控制器绑定到AnimatedPositioned上  duration: _controller.duration, // 使用AnimationController的持续时间,确保动画同步。  x: 0, // x位置保持不变,仅y位置进行动画处理。  y: _tween.value, // 使用Tween的值作为y位置。随着动画的进行,y位置会从0变化到200。  child: Container(  width: 100,  height: 100,  color: Colors.red,  ),  ),  ],  );  }  
}

这些动画都是一些动画元素,可以将多个动画元素组装成复杂动画(Complex Animations),通常指交错动画、序列动画、交错动画、组合动画等;
除了使用系统提供的组件去构建动画外,我们还可以使用CustomPainter构建自定义路径动画。

自定义路径动画

自定义路径动画可以根据需要绘制任何形状的路径,并在动画中改变路径的形状、位置和颜色等属性实现相应的效果。

class MyPainter extends CustomPainter {    bool shouldRepaint(CustomPainter oldDelegate) {  // 返回true表示需要重新绘制,这里我们简单地将返回true,以便每次重新渲染时都会重新绘制路径。  return true;  }    void paint(Canvas canvas, Size size) {  // 获取屏幕的宽高,以便根据需要调整绘制的比例。  var paint = Paint()..strokeCap = StrokeCap.round;  paint.strokeWidth = 10.0;  paint.color = Colors.red; // 设置画笔颜色为红色。  // 创建路径并绘制。这里我们只是简单地将一个圆形的路径绘制在屏幕上。您可以根据需要创建复杂的路径。  var path = Path()..moveTo(0, 0)..circle(size.width / 2, size.height / 2, size.width / 4); // 在屏幕中心绘制一个圆形的路径。您可以根据需要修改路径的形状和位置。  canvas.drawPath(path, paint);  }  
}

除此之外,还可以通过使用Flutter对应的动画库来创建动画。

spring_simulation

spring_simulation是一种物理模拟器,用于创建具有弹簧效果的动画;
它基于弹簧动力学原理,通过模拟弹簧的伸展、压缩和反弹等行为,实现动画的逼真效果。

class MyApp extends StatelessWidget {    Widget build(BuildContext context) {  return MaterialApp(  title: 'SpringSimulation Example',  theme: ThemeData(primarySwatch: Colors.blue),  home: Scaffold(  appBar: AppBar(title: Text('SpringSimulation Example')),  body: Center(  child: SpringSimulation(  // 定义弹簧模拟器的参数  mass: 1.0, // 质量(kg)  stiffness: 400.0, // 刚度(N/m)  damping: 5.0, // 阻尼(N·s/m)  target: 0.0, // 目标位置(m)  // 定义弹簧的初始位置和速度  initialPosition: -1.0, // 初始位置(m)  initialVelocity: 2.0, // 初始速度(m/s)  // 定义弹簧的约束条件(可选)  constraints: SpringConstraints(min: -1.0, max: 1.0), // 限制弹簧的最小和最大位置范围  // 将弹簧附加到屏幕上,这里使用了一个简单的圆点作为示例  onUpdate: (mass, stiffness, damping, position, velocity) {  Positioned(  left: position * 300, // 将弹簧的位置转换为屏幕坐标  child: Container(  width: 30,  height: 30,  decoration: BoxDecoration(shape: BoxShape.circle), // 创建一个圆点作为弹簧的表示  child: Icon(Icons.play_arrow), // 使用播放箭头图标作为示例,您可以根据需要自定义图标或文本等UI元素。  ),  );  },  ),  ),  ),  );  }  
}

还有很多,就不一一列举了。
在Flutter开发中构建动画,需要注意的点是:
选择合适的动画库
根据项目需求选择合适的动画库,如Tween、Dart-Animation-Lib、flutter_animator等。
理解动画生命周期
Flutter中的动画有一个开始、执行和结束的过程。你需要确保在动画开始时设置动画的初始状态,并在动画结束时设置动画的结束状态。
使用状态管理
Flutter中的动画通常与状态变化相关联,因此,建议使用Flutter的状态管理解决方案,如Redux或Bloc,来管理动画状态。
优化性能
在构建动画时,需要注意性能问题,避免在动画执行期间进行不必要的渲染或计算操作,这可能导致动画卡顿。
测试不同设备和场景
在不同设备和不同场景下测试动画效果,以确保动画在不同环境下都能正常工作。
考虑用户反馈
根据用户反馈调整动画效果,以提供更好的用户体验。
遵循Material Design规范
如果项目需要遵循Material Design规范,确保动画效果与规范保持一致。

如何对动画优化性能

对于Flutter开发中的性能优化,有以下几个方向。
避免不必要的渲染和计算
在动画执行期间,应避免进行不必要的渲染或计算操作,这可以减少GPU和CPU的工作负担,提高动画性能;
比如使用Reusable或MemoizedListTile等复用组件,这些组件可以在列表中使用,避免在列表滚动时重复创建和销毁组件,从而提高性能;
使用const关键字,在可能的情况下,尽量使用const关键字来创建不可变对象,这样可以避免在动画执行期间进行不必要的重新构建;
避免在动画执行期间进行复杂的布局和计算,在动画执行期间,应避免进行复杂的布局和计算操作,这些操作可能会导致不必要的渲染和计算;
使用ListView的physics属性,通过设置physics属性为NeverScrollableScrollPhysics(),可以避免在滚动时触发不必要的布局和渲染;
使用WidgetsBinding.instance.addPostFrameCallback,这个方法可以用来在每一帧渲染后执行回调函数,可以在这里进行一些必要的计算和更新操作,避免在动画执行期间进行不必要的渲染和计算;
使用Binding.instance.addPostFrameCallback,这个方法与WidgetsBinding.instance.addPostFrameCallback类似,但作用范围更广,可以在整个应用中避免不必要的渲染和计算。
使用列表复用
在处理大量数据时,使用列表复用技术可以避免频繁创建和销毁列表项,从而提高性能;
比如通过使用ListTile的key属性,可以确保列表项的唯一性,从而实现列表复用;
另外,也可以使用Reusable组件或MemoizedListTile组件来实现列表复用。
使用GPU加速
Flutter的渲染引擎支持GPU加速,通过将部分或全部渲染工作交给GPU处理,可以提高动画性能。
优化Widget树
在构建动画时,应尽量减少Widget树的深度和复杂度,避免不必要的布局和重绘操作,从而提高性能。
使用帧调度器
通过使用Flutter的帧调度器,可以更好地控制动画的执行时间和帧率,从而提高性能。
使用Profile工具
Flutter提供了Profile工具,可以用来分析应用的性能瓶颈,通过使用Profile工具,可以找到性能问题并进行针对性的优化。
使用高性能的动画库
如Tween等高性能的动画库,可以提供更好的动画性能。

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

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

相关文章

Spring之AOP源码(二)

书接上文 文章目录 一、简介1. 前文回顾2. 知识点补充 二、ProxyFactory源码分析1. ProxyFactory2. JdkDynamicAopProxy3. ObjenesisCglibAopProxy 三、 Spring AOP源码分析 一、简介 1. 前文回顾 前面我们已经介绍了AOP的基本使用方法以及基本原理&#xff0c;但是还没有涉…

2023年全国职业院校技能大赛软件测试赛题—单元测试卷⑤

单元测试 一、任务要求 题目1&#xff1a;根据下列流程图编写程序实现相应处理&#xff0c;执行j10*x-y返回文字“j1&#xff1a;”和计算值&#xff0c;执行j(x-y)*(10⁵%7)返回文字“j2&#xff1a;”和计算值&#xff0c;执行jy*log(x10)返回文字“j3&#xff1a;”和计算值…

openssl3.2 - 官方demo学习 - encrypt - rsa_encrypt.c

文章目录 openssl3.2 - 官方demo学习 - encrypt - rsa_encrypt.c概述笔记END openssl3.2 - 官方demo学习 - encrypt - rsa_encrypt.c 概述 从内存中的DER共钥数据构造pub_key, 用公钥加密明文, 输出密文. 非对称加密 从内存中的DER私钥数据构造priv_key, 用私钥解密密文, 输出…

经典目标检测YOLO系列(二)YOLOv2算法详解

经典目标检测YOLO系列(二)YOLOv2算法详解 YOLO-V1以完全端到端的模式实现达到实时水平的目标检测。但是&#xff0c;YOLO-V1为追求速度而牺牲了部分检测精度&#xff0c;在检测速度广受赞誉的同时&#xff0c;其检测精度也饱受诟病。正是由于这个原因&#xff0c;YOLO团队在20…

TIDB: 元数据查询语句

一、获取表描述 select table_name,table_comment from information_schema.TABLES where table_schema %s and table_name in (%s)二、获取视图DDL SELECT * FROM information_schema.views WHERE TABLE_NAME %s and TABLE_SCHEMA %s三、判断表是否存在sql select table…

clickhouse join查询算法

算法对比&#xff1a; 使用方法&#xff1a; SELECT town,max(price) AS max_price,any(population) AS population FROM uk_xxx_paid JOIN uk_xxx_table ON lower(uk_price_paid.town) lower(uk_populations_table.city) GROUP BY town ORDER BY max_price DESC SETTINGS jo…

PLC-IoT 网关开发札记(3):Xamarin Forms 首页跳转的正确姿势

1. 需求 使用 Xamarin.Forms 默认的模板生成卡片式 App 项目后&#xff0c;App 打开的是第一个卡片页。实用中&#xff0c;往往需要 App 启动后呈现一个 Splash&#xff0c;在 Splash 页面的后台完成系统初始化的一些任务&#xff0c;然后自动跳转或者等待用户点击 “立即体验…

代码随想录 Leetcode349. 两个数组的交集

题目&#xff1a; 代码(首刷看解析 2024年1月14日&#xff09;&#xff1a; class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> a;unordered_set<int> res;for(int i 0…

Centos7 安装与卸载mysql

卸载 ps ajx | grep mysql &#xff1a; 查看当前服务器是否有mysql 没有的话就不需要卸载咯。 centos7 通过yum下载安装包通常是以.rpm为后缀&#xff0c;rpm -qa 可以查看当前服务器上所有的安装包&#xff1a; rpm -qa | grep mysql | xargs yum -y remove :将查询到的mysql…

AI辅助编程:同义千问挑战力扣

大家好我是在看&#xff0c;记录普通人学习探索AI之路。 今天我们来聊一聊如何使用AI进行辅助编程。 ChatGPT对于各行各业都带来了工作效率的提升&#xff0c;尤其是程序员这一行。因为ChatGPT可以帮助程序员来生成各种各样的程序代码。 我们先来看一个简单的例子&#xff0c…

多行SQL转成单行SQL

如下图所示 将以上多行SQL转成单行SQL 正则表达式如下 (?s)$[^a-zA-Z()0-9]*结果如下 灵活使用,也未必只能使用Sublime Text

js null和undefined的区别

null和undefined在JavaScript中都表示“无”的概念&#xff0c;但它们在使用和含义上有一些重要的区别。 含义&#xff1a; null 是一个表示“无”的对象&#xff0c;当转换为数值时结果为0。 undefined 是一个表示“缺少值”的原始值&#xff0c;当转换为数值时结果为NaN。…

用java写个redis工具类

下面是一个简单的Redis工具类的示例&#xff0c;使用Java语言编写&#xff1a; import redis.clients.jedis.Jedis;public class RedisUtils {private static Jedis jedis;public static void connect(String host, int port) {jedis new Jedis(host, port);}public static v…

python爬虫01-爬虫介绍

目录 1、爬虫是什么 2、爬虫有什么用 3、爬虫的步骤 4、网页的渲染方式 1、爬虫是什么 爬虫就是写一段代码运行去模仿人访问网站。可以代替人们自动的在互联网进行数据采集和整理。 2、爬虫有什么用 数据采集&#xff1a;爬虫可以自动访问网页并抓取其中的数据&#xff0…

基于卡尔曼滤波的视频跟踪,基于卡尔曼滤波的运动小球跟踪

目录 完整代码和数据下载链接&#xff1a;基于卡尔曼滤波的视频跟踪&#xff0c;基于卡尔曼滤波的运动小球跟踪&#xff08;代码完整&#xff0c;数据齐全&#xff09;资源-CSDN文库 https://download.csdn.net/download/abc991835105/88738577 卡尔曼滤波原理 RBF的定义 RBF理…

ajax+axios——统一设置请求头参数——添加请求头入参——基础积累

最近在写后台管理系统&#xff08;我怎么一直都只写管理系统啊啊啊啊啊啊啊&#xff09;&#xff0c;遇到一个需求&#xff0c;就是要在原有系统的基础上&#xff0c;添加一个仓库的切换&#xff0c;并且需要把选中仓库对应的id以请求头参数的形式传递到每一个接口当中。。。 …

4.【CPP】入门(初始化列表||explicit||static||友元||静态成员变量/函数)

一.初始化列表 1.引入 我们知道在c11中才能在成员对象声明时初始化&#xff0c;像下面这样。 class Date { public: Date(int year, int month, int day): _year(year), _month(month), _day(day) {} private: int _year2000; int _month12; int _day20; };注意&#xff1a;…

Redis:原理速成+项目实战——Redis实战9(秒杀优化)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis实战8&#xff08;基于Redis的分布式锁及优化&#xff09; &#x1f4da;订阅专栏&…

浅谈一谈pytorch中模型的几种保存方式、以及如何从中止的地方继续开始训练;

一、本文总共介绍3中pytorch模型的保存方式&#xff1a;1.保存整个模型&#xff1b;2.只保存模型参数&#xff1b;3.保存模型参数、优化器、学习率、epoch和其它的所有命令行相关参数以方便从上次中止训练的地方重新启动训练过程。 1.保存整个模型。这种保存方式最简单&#x…