Flutter 高级动画技术综合指南

news2024/11/18 9:41:11

在动画领域,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.coloradmin.cn/o/1419421.html

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

相关文章

Hana SQL+正则表达式

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

【openGauss】openEuler 22.03 LTS 安装了openGauss数据库后yum不可用

问题描述 尝试使用yum时出现依赖包缺少依赖版本的问题&#xff0c;主要问题时在安装openGauss时&#xff0c;通过脚本创建omm用户和dbgrp组导致的&#xff0c;如果用户和组是提前创建好的就不会出现这样的问题 报错&#xff1a;version GLIBCXX_3.4.26’ not found 报错信息 …

计算机视觉:高级图像处理,满足您的所有需求。

一、说明 特征提取是机器学习管道中的关键步骤&#xff0c;可增强模型在不同数据集上的泛化和良好表现能力。特征提取方法的选择取决于数据的特征和机器学习任务的具体要求。本文揭示图像处理的数学原理&#xff0c;实现增强的计算机视觉 二、关于计算机视觉的普遍问题 在计算机…

DL/T645、IEC104转MQTT网关BE113

随着电力系统信息化建设和数字化转型的进程不断加速&#xff0c;对电力能源的智能化需求也日趋增强。健全稳定的智慧电力系统能够为工业生产、基础设施建设以及国防建设提供稳定的能源支持。在此背景下&#xff0c;高性能的工业电力数据传输解决方案——协议转换网关应运而生&a…

【动态规划】【图论】【C++算法】1575统计所有可行路径

作者推荐 【动态规划】【字符串】【行程码】1531. 压缩字符串 本文涉及知识点 动态规划汇总 图论 LeetCode1575统计所有可行路径 给你一个 互不相同 的整数数组&#xff0c;其中 locations[i] 表示第 i 个城市的位置。同时给你 start&#xff0c;finish 和 fuel 分别表示出…

github添加 SSH 密钥

1 打开终端 输入 ssh-keygen -t rsa -b 4096 -C "github邮箱地址"如果不需要密码可以一路回车 出现这个页面就是生存成功了 open ~/.ssh // 打开.ssh 找到id_rsa.pub复制出内容新建ssh密钥输入内容,保存即可

JavaWeb中的Filter(过滤器)和 Listener(监听器)

提示&#xff1a;这两个东西听起来似乎很难&#xff0c;实际上是非常简单的&#xff0c;按照要求写就行了&#xff0c;一定不要被新名词给吓到了。 JavaWeb中的Filter&#xff08;过滤器&#xff09; 一、Filter&#xff08;过滤器&#xff09;1.如何编写 Filter2.Filter 中的细…

webassembly003 TTS BARK.CPP

TTS task TTS&#xff08;Text-to-Speech&#xff09;任务是一种自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;其中模型的目标是将输入的文本转换为声音&#xff0c;实现自动语音合成。具体来说&#xff0c;模型需要理解输入的文本并生成对应的语音输出&#xff0…

Day01-变量和数据类型课后练习-参考答案

文章目录 1、输出你最想说的一句话&#xff01;2、定义所有基本数据类型的变量和字符串变量3、用合适类型的变量存储个人信息并输出4、定义圆周率PI5、简答题 1、输出你最想说的一句话&#xff01; 编写步骤&#xff1a; 定义类 Homework1&#xff0c;例如&#xff1a;Homewo…

85 C++对象模型探索。数据语义学 - 继承多个类,且是虚基类的数据内存模型分析。虚基类表,虚基类表指针

前面我们分析了 继承多个类的情况。上一次分析的这样的情况&#xff1a; 今天看虚基类。先复习一下虚基类&#xff1a;类似下面这样的图 复习虚基类可以解决的问题&#xff1a; 在这之前先要复习一下多继承同一个爷爷类时带来的问题 空间问题 效率问题 二义性问题 //虚基类问…

数据库管理-第141期 DG PDB - Oracle DB 23c(20240129)

数据库管理141期 2024-01-29 第141期 DG PDB - Oracle DB 23c&#xff08;20240129&#xff09;1 概念2 环境说明3 操作3.1 数据库配置3.2 配置tnsname3.3 配置强制日志3.4 DG配置3.5 DG配置建立联系3.6 启用所有DG配置3.7 启用DG PDB3.8 创建源PDB的DG配置3.9 拷贝pdbprod1文件…

TCP/IP网络模型

大家好我是苏麟 , 今天聊聊TCP/IP四层网络模型 . 资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 应用层 最上层的&#xff0c;也是我们能直接接触到的就是应用层&#xff08;Application Layer&#xff09;&#xff0c;我们电脑或手机使用的应用软件都…

测试ASP.NET Core项目调用EasyCaching的基本用法(InMemory)

EasyCaching属于开源缓存库&#xff0c;支持基本缓存方式及高级缓存用法&#xff0c;提高用户操作缓存的效率。EasyCaching支持的缓存方式包括以下类型&#xff0c;本文学习最基础的InMemory方式的基本用法。   EasyCaching.InMemory包属于基于内存的缓存库&#xff0c;使用的…

C语言——指针进阶(四)

目录 一.前言 二.指针和数组笔试题解析 2.1 二维数组 2.2 指针笔试题 三.全部代码 四.结语 一.前言 本文我们将迎来指针的结尾&#xff0c;包含了二维数组与指针的试题解析。码字不易&#xff0c;希望大家多多支持我呀&#xff01;&#xff08;三连&#xff0b;关注&…

JavaWeb后端登录校验功能(JWT令牌技术,Cookie技术,Session,拦截技术,过滤器)

目录 一.登录校验功能&#xff08;解决直接通过路径访问&#xff09; 1.实现思路 二.会话技术 ​编辑 1.Cookie技术 2.Session 3.令牌技术 1.简介 2.如何生成和解析 3.令牌的使用 三.Filter过滤器 1.什么是过滤器 2.实现步骤&#xff1a; 3.过滤器执行流程 4.拦截路径 5.过…

349. 两个数组的交集(力扣LeetCode)

文章目录 349. 两个数组的交集题目描述数组解题set容器解题该思路数组版解题 349. 两个数组的交集 题目描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&a…

【Linux】Linux下多线程

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 前置&#xff1a;进程地址空间和页表1.1 如何看待进程地址空间和页表1.2 虚拟地址…

练习12.6_横向射击_Python编程:从入门到实践(第3版)

编写一个游戏&#xff0c;将一艘飞船放在屏幕左侧&#xff0c;并允许玩家上下移动飞船。在玩家按空格键时&#xff0c; 让飞船发射一颗在屏幕中向右飞行的子弹&#xff0c;并在子弹从屏幕中消失后将其删除。 ship_shooting.py import pygame import sys from leftship impor…

​ArcGIS Pro 如何批量删除字段

在某些时候&#xff0c;我们得到的图层属性表内可能会有很多不需要的字段&#xff0c;如果挨个去删除会十分的麻烦&#xff0c;对于这种情况&#xff0c;我们可以使用工具箱内的字段删除工具批量删除&#xff0c;这里为大家介绍一下使用方法&#xff0c;希望能对你有所帮助。 …

[C++历练之路]C++中的继承小学问

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; C中&#xff0c;继承是一种面向对象编程的重要概念&#xff0c;它允许一个类&#xff08;子类/派生类&#xff09;从另一个类&#xff08;父类/基类&#xff09;继承属性和方法。继承是…