Flutter 高级动画技术综合指南

在动画领域,Flutter 提供了一系列功能,包括基于物理的动画,可以模拟真实世界的动态,在应用程序中创建更逼真和自然的运动。

本文将深入研究 Flutter 动画,探索各种类型,并演示如何在项目中实现它们。

Flutter 的动画系统围绕着一个“Animation 对象”的概念,这个对象的值会随着时间而变化,这个变化由一个“AnimationController”来控制,它定义了动画的持续时间、方向和其他参数,要设置一个动画,这两个元素必须连接起来。

常用的动画类

以下是在 Flutter 中创建动画时经常使用的一些关键类:

  • Tween:定义动画在其间进行插值的值范围。例如,它可以指定动画的开始值和结束值。
  • AnimationController:这个类控制动画进程,允许你启动、停止和重启动画,以及配置动画的持续时间和曲线。
  • AnimatedBuilder:这个小部件在动画发生变化时会重新构建自身,对于制作包含多个小部件的复杂动画特别有用。
  • Curve:Curve(曲线)决定了动画的进度,Flutter 提供了内置的曲线,如 LinearProgressIndicatorCurves.easeInOut ,或者你可以设计自己的自定义曲线。

基于物理的动画

Flutter 提供了 Simulation 类,用于创建具有初始状态和演化规则的基于物理的模拟,这个类使你能够制作各种基于物理的动画,包括基于弹簧动力学、摩擦力和重力的动画。

让我们考虑 Flutter 中基于物理的动画的示例:弹簧动画。 SpringSimulation 类可用于创建此动画,模拟阻尼谐振子。以下是如何使用 SpringSimulation 生成类似弹簧的动画:

// Import required packages
import 'package:flutter/material.dart';// 定义一个 SpringAnimation 小部件
class SpringAnimation extends StatefulWidget {const SpringAnimation({Key? key});_SpringAnimationState createState() => _SpringAnimationState();
}
class _SpringAnimationState extends State<SpringAnimation> with SingleTickerProviderStateMixin {late final AnimationController _controller = AnimationController(vsync: this,duration: const Duration(seconds: 3),)..forward();late final Animation<double> _animation = Tween<double>(begin: 0,end: 400,).animate(CurvedAnimation(parent: _controller,curve: Curves.elasticOut,));void _startAnimation() {_controller.reset();_controller.forward();}Widget build(BuildContext context) {return MaterialApp(home: Scaffold(body: Center(child: AnimatedBuilder(animation: _animation,builder: (context, child) {return Stack(children: [Positioned(left: 70,top: _animation.value,child: child!,)],);},child: GestureDetector(onTap: () {_startAnimation();},child: Container(height: 100,width: 250,decoration: BoxDecoration(color: const Color(0xFF00EF3C),borderRadius: BorderRadius.circular(10),),child: const Center(child: Text('SEMAPHORE',style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),)),),),),),),);}void dispose() {_controller.dispose();super.dispose();}
}

在这个例子中, SpringAnimation 小部件使用 AnimationController 来驱动 Animation 对象, Tween 定义了动画的值范围, CurvedAnimationCurves.elasticOut 赋予了动画一个弹性缓动曲线, AnimatedBuilder 小部件用于根据动画的值来动画 Container 小部件的位置, Positioned 小部件确保 Container 小部件在屏幕上的位置与动画的值相关,当小部件被构建时, AnimationController 启动了 Animation 对象的值动画,从而推动了 Container 小部件的位置动画。

结果是一个迷人的弹簧般的动画,在屏幕上产生弹跳效果。从本质上讲,基于物理的动画为您提供了一种强大的机制,可以在您的应用程序中制作逼真且流畅的动作,而 Flutter 提供了一系列工具和类来促进其实现。

Hero 动画

Flutter 中的 Hero 小部件充当不同屏幕之间共享元素转换的管道。例如,Hero 小部件可以以动画方式将小部件从一个屏幕过渡到另一个屏幕,包含图像、文本甚至容器等多种元素。该小部件通过为共享元素设置动画来促进无缝过渡。

Hero 小部件的一个关键方面是要求在起始和目标屏幕上都具有相同的标签,这个标签对于识别正在进行转换的共享元素至关重要。

考虑下面的示例,它演示了如何利用 Hero 小部件实现图像缩略图和全屏视图之间的平滑过渡。

缩略图屏幕

import 'package:flutter/material.dart';class ThumbnailScreen extends StatelessWidget {const ThumbnailScreen({super.key});Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Thumbnail Screen'),),body: Column(children: [GridView.count(crossAxisSpacing: 15,crossAxisCount: 2,children: [Hero(tag: 'image1',child: GestureDetector(onTap: () {Navigator.push(context,MaterialPageRoute(builder: (context) => const FullScreenScreen(imageAsset: 'assets/white_puma.jpg',heroTag: 'image1',),),);},child: Image.asset('assets/white_puma.jpg'),),),Hero(tag: 'image2',child: GestureDetector(onTap: () {Navigator.push(context,MaterialPageRoute(builder: (context) => const FullScreenScreen(imageAsset: 'assets/red_nike.jpg',heroTag: 'image2',),),);},child: Image.asset('assets/red_nike.jpg',),),),],),],),);}
}

屏幕全屏

class FullScreenScreen extends StatelessWidget {final String imageAsset;final String heroTag;const FullScreenScreen({super.key, required this.imageAsset, required this.heroTag});Widget build(BuildContext context) {return Scaffold(body: GestureDetector(onTap: () {Navigator.pop(context);},child: Hero(tag: heroTag,child: Image.asset(imageAsset),),),);}
}

ThumbnailScreen 中,Hero 小部件封装了 Image 小部件,每个小部件都有一个独特的标签来区分共享元素。当用户与图像交互时,导航操作将他们引导到 FullScreenScreen

FullScreenScreen 中,图像被另一个 Hero 小部件包围,它与 ThumbnailScreen 中对应的图像具有相同的标签。这个标签控制着图像从缩略图屏幕到全屏显示的动画。此外,图像嵌套在一个GestureDetector中,使用户可以点击屏幕上的任何地方以恢复到缩略图屏幕。

当用户点击 ThumbnailScreen 上的图像时,Flutter 会编排一个动画,将共享元素传输到 FullScreenScreen 上。当用户点击 FullScreenScreen 上的图像时,Flutter 会执行一个动画,将共享元素返回到 ThumbnailScreen 上。Hero 小部件在渲染屏幕之间的无缝和迷人的过渡方面被证明是无价的,它对于增强电子商务应用程序的用户体验尤其有效。

隐式的动画

隐式动画是在 Flutter 中生成简单动画的重要工具,可响应小部件属性的变化。与深入研究复杂的动画控制器和微调器相比,隐式动画使您能够对小部件的属性制作动画,而无需关心动画的复杂细节。AnimatedContainer 小部件就是隐式动画工具的一个典型例子。

AnimatedContainer 小部件类似于标准的容器,但它拥有额外的动画功能,它可以动画地改变属性,如大小、颜色和形状,让我们通过一个示例来演示如何使用 AnimatedContainer 小部件在按钮被按下时动画地改变颜色。

隐式动画示例

// Import required packages and libraries
import 'package:flutter/material.dart';// Define the ImplicitAnimations widget
class ImplicitAnimations extends StatefulWidget {const ImplicitAnimations({Key? key}) : super(key: key);createState() => ImplicitAnimationsState();
}
class ImplicitAnimationsState extends State<ImplicitAnimations> {bool _isPressed = false;void _togglePressed() {setState(() {_isPressed = !_isPressed;});}Widget build(BuildContext context) {return MaterialApp(home: Scaffold(appBar: AppBar(title: const Text('Color and Position Change'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [AnimatedContainer(duration: const Duration(seconds: 1),height: 200.0,width: 200.0,margin: EdgeInsets.only(top: _isPressed ? 70.0 : 0.0,),decoration: BoxDecoration(color: _isPressed ? Colors.blue : Colors.red,borderRadius: BorderRadius.circular(_isPressed ? 50.0 : 0.0),),),const SizedBox(height: 20.0),ElevatedButton(onPressed: _togglePressed,child: const Text('ANIMATE'),),],),),),);}
}

在本例中,ImplicitAnimations 部件包含一个 _isPressed 布尔变量和一个 _togglePressed() 函数,用于切换布尔变量的值。该部件的状态类在 _togglePressed() 中调用了 setState(),以便在值发生变化时触发部件树的重建。

这个小部件的结构围绕着一个位于 Scaffold 中的 Center 小部件,这个 Center 小部件容纳了一个 Column ,它包含两个主要元素:

  1. AnimatedContainer。该小部件根据 _isPressed 值为其属性设置动画。在此示例中,高度、宽度、边距、颜色和边框半径的更改均以动画形式呈现。
  2. ElevatedButton。该按钮按下时会激活动画,调用 _togglePressed() 函数来切换 _isPressed

隐式动画是一种用户友好的方法,可以将动画引入 Flutter 应用程序,而无需复杂的动画控制器和渐变。

动画矢量图形

Flutter 通过不同的工具支持矢量动画图形,这进一步体现了 Flutter 制作复杂动态动画的能力。基于矢量的图形在调整大小后仍能保持质量。Flutter 利用不同的工具来创建动画并将其导入应用程序。

Rive

Rive 提供了一种制作跨平台动画的方法,从移动到 Web。Rive 动画可以导出为 Rive 文件,可以通过 Rive 包集成到您的 Flutter 项目中。该包还提供了一个 Rive 小部件来展示应用程序中的 Rive 动画。

让我们深入研究在 Flutter 应用中实现 Rive 的过程:

// Import required packages and libraries
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';// Define the RiveAnimations widget
class RiveAnimations extends StatelessWidget {const RiveAnimations({Key? key}) : super(key: key);Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.grey,body: Center(child: Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(20),color: Colors.blue,),width: 300,height: 300,child: const RiveAnimation.asset('assets/ball.riv'),),),);}
}

要使用 Rive 在 Flutter 动画中加入动画矢量图形,请按照以下步骤操作:

  1. 使用 rive 网站创建动画并以适当的格式下载。
  2. 将 Rive 包导入到你的 Flutter 项目中。
  3. 利用 RiveAnimation.asset 小部件,提供 Rive 文件的路径。

动画可以使用 RiveAnimationController 类进行控制,允许您根据需要启动、停止和暂停动画。

上面的动画是用 rive 制作的,它演示了一个球被弹起和踢出,但它并没有描绘 rive 的所有属性。Rive 可以用来为你的动画设置不同的状态,这让你的动画更动态。你可以让动画对应用程序的状态做出反应,但你必须擅长动画,才能利用 rive 的这一方面。除了 Rive,你还可以探索其他工具,如 Lottie,将预先构建的动画集成到 Flutter 应用程序中。

Lottie 动画

Lottie 是一个流行的库,它允许你使用 Adobe After Effects 等动画工具生成的 JSON 文件在应用中渲染动画。Lottie 动画是基于矢量的,提供流畅和高质量的视觉体验。在 Flutter 中,您可以使用 Lottie 包集成 Lottie 动画,它提供了 Lottie.assetLottie.network 小部件。

下面是一个如何在 Flutter 中创建 Lottie 动画的示例:

// Import required packages and libraries
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';// Define the LottieAnimations widget
class LottieAnimations extends StatelessWidget {const LottieAnimations({Key? key});Widget build(BuildContext context) {return Scaffold(body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [const SizedBox(height: 50),SizedBox(height: 200,width: 200,child: LottieBuilder.asset('assets/shopping.json'),),const SizedBox(height: 50),const Text('add items to cart',style: TextStyle(fontSize: 30),),],),),);}
}

Lottie 动画轻松让您的应用程序栩栩如生。只需找到或创建 Lottie 格式 (JSON) 所需的动画,导入 Lottie 包,然后使用提供的小部件在 Flutter 应用程序中展示您的动画。

结论

动画在移动应用程序开发中发挥着关键作用,通过为应用程序注入活力和参与度来增强用户体验。本文深入探讨了 Flutter 的动画功能,从动画系统和基本类到基于物理的动画、自定义动画和使用 Hero 小部件的动画过渡等高级技术。我们还讨论了隐式动画以及使用 Rive 和 Lottie 等包集成动画矢量图形。

通过利用这些资源,你可以深入研究 Flutter 动画的世界,制作迷人的动态用户界面,使你的移动应用程序与众不同。

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

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

相关文章

Linux系统Shell脚本-----------正则表达式 、grep、 sed

一、正则表达式 1.前言 正则表达式(regular expression)描述了一种字符串匹配的模式&#xff08;pattern&#xff09;&#xff0c;可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。在Linux中也就是代表我们定义的模式模板&…

vue实现跳转传参查询

vue实现跳转传参查询&#xff1a; 应用场景&#xff1a;外部链接携参跳转目标页时,避免多次输入查询信息查询 目标需求&#xff1a;登录及非登录状态均可跳转自动查询 避坑指南&#xff1a;token失效时需要重新缓存及路由导航缓存判断 简单实现&#xff1a;缓存信息&#xff0c…

LLM之makeMoE:makeMoE的简介、安装和使用方法、案例应用之详细攻略

LLM之makeMoE&#xff1a;makeMoE的简介、安装和使用方法、案例应用之详细攻略 目录 makeMoE的简介 1、对比makemore 2、相关代码文件 makMoE_from_Scratch.ipynb文件 makeMoE_Concise.ipynb文件 makeMoE的安装和使用方法 1、基于Databricks使用单个A100进行开发 makeM…

线程锁多线程的复习

线程 实现方式3种乐观锁&悲观锁线程池线程池总结 进程:是正在运行的程序 线程:是进程中的单个顺序控制流,是一条执行路径 实现方式3种 1.Thread //步骤一:定义一个继承Thread的类 //步骤二:再定义的类中重写run()方法 //步骤三:创建定义类对象 //步骤四:启动线程 class M…

Armv8-M的TrustZone技术之在安全状态和非安全状态之间切换

Armv8-M安全扩展允许在安全和非安全软件之间直接调用。 Armv8-M处理器提供了几条指令来处理状态转换: 下图显示了安全状态转换。 如果入口点的第一条指令是SG且位于非安全可调用内存位置中,则允许从非安全到安全软件的直接API函数调用。 当非安全程序调用安全API时,API通过…

vue中的vuex

在Windows的应用程序开发中&#xff0c;我们习惯了变量&#xff08;对象&#xff09;声明和使用方式&#xff0c;就是有全局和局部之分&#xff0c;定义好了全局变量&#xff08;对象&#xff09;以后在其他窗体中就可以使用&#xff0c;但是窗体之间的变量&#xff08;对象&am…

20240129收获

今天终于发现《八部金刚功》第五部我一直做的是错的&#xff0c;嗨。这里这个写法非常聪明&#xff0c;创立的数组&#xff0c;以及用obj[key] item[key]这样的写法&#xff0c;这个写法充分展示了js常规写法中只有等号右边会去参与运算&#xff0c;等号左边就是普通的键的写法…

项目实现网页分享QQ空间功能

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f380;源码如下&#xff1a; &#x1f412;个人主页 &#x1f3c5;Vue项目常用组件模板仓库 &#x1f4d6;前言&#xff1a; 本篇博客主要提供“点击转发按钮&#x…

TensorFlow2实战-系列教程9:RNN文本分类1

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 1、文本分类任务 1.1 文本分类 数据集构建&#xff1a;影评数据集进行情感分析&…

Hana SQL+正则表达式

目录 一、Pre 前言 二、知识点拆解 1&#xff09;case when…then…else 2&#xff09;json_value 函数 拓展资料 3&#xff09;CAST 函数 拓展资料 4) ROUND 函数 5&#xff09;occurences_regexpr 函数 拓展资料 6&#xff09;正则表达式 拓展资料 三、整合分析…

10s 内得到一个干净、开箱即用的 Linux 系统

安装 使用官方脚本安装我的服务器不行 官方脚本 mkdir instantbox && cd $_ bash <(curl -sSL https://raw.githubusercontent.com/instantbox/instantbox/master/init.sh) 下面是我的完整安装过程 mkdir /opt/instantbox cd /opt/instantbox 1.脚本文件 (这个没…

[PHP]严格类型

PHP: 类型声明 - Manual

【学网攻】 第(15)节 -- 标准ACL访问控制列表

系列文章目录 目录 系列文章目录 文章目录 前言 一、ACL(访问控制列表)是什么? 二、实验 1.引入 实验拓扑图 实验配置 测试PC2能否Ping通PC3 配置ACL访问控制 实验验证 PC1 Ping PC3 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认…

Spring Boot导出EXCEL 文件

主要功能:实现java导出excel到本地 JDK版本&#xff1a;openJDK 20.0.1 依赖pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchem…

Java 面试题之 IO(一)

字节流 文章目录 字节流InputStream&#xff08;字节输入流&#xff09;OutputStream&#xff08;字节输出流&#xff09; 文章来自Java Guide 用于学习如有侵权&#xff0c;立即删除 InputStream&#xff08;字节输入流&#xff09; InputStream用于从源头&#xff08;通常是…

Centos Cron设置定时任务

这本是很简单的问题&#xff0c;但是我服务器重装系统两次&#xff0c;遇到的问题都不一样&#xff0c;所以记录一下 1.首先要确保服务器上有 cron 服务 sudo systemctl status crond2.设置时区 sudo timedatectl set-timezone Asia/Shanghai3.重启crond 服务使crond服务的时…

Xds (eXtensible Discovery Service)理解

Xds &#xff08;eXtensible Discovery Service&#xff09;理解 概念介绍 XDS&#xff1a;全称是 eXtensible Discovery Service&#xff0c;中文译为”可扩展的服务发现“。是一个扩展性的协议&#xff0c;可以用于配置和控制 Envoy 代理的各个方面&#xff0c;包括路由规则…

Leetcode 206 反转链表

反转链表 准备工作1&#xff09;ListNode基本结构2&#xff09;初始化ListNode集合 解法一&#xff1a;遍历创建新节点解法二&#xff1a;两组List&#xff0c;面向对象操作解法三&#xff1a;递归调用解法四&#xff1a;直接移动解法五&#xff1a;解法二的面向过程 Leetcode …

Ubuntu 20.04 Server 使用命令行设置 IP 地址

1、编辑 /etc/netplan/ 目录下的配置文件00-installer-config.yaml (修改之前&#xff0c;把原来的文件备份) 按照对应的配置进行修改IP地址和网关 2、运行命令使其生效 sudo netplan apply 修改完成后&#xff0c;永久有效。重启后配置不会丢失

【智能家居入门之微信小程序控制下位机】(STM32、ONENET云平台、微信小程序、HTTP协议)

实现微信小程序控制单片机外设动作 一、使用ONENET可视化组件控制单片机外设动作二、使用微信小程序控制单片机外设动作三、总结 本篇博客话接上文&#xff1a; https://blog.csdn.net/m0_71523511/article/details/135892908 上一篇博客实现了微信小程序接收单片机上传的数据…