Flutter:动画

news2024/11/27 17:56:24

前言

学习参考:老孟 flutter动画
基本上开发时使用的组件都有其动画,关于动画方面的知识,一般情况很少会用到。因此这里只学习关于动画的基本知识。

AnimationController

Flutter中的AnimationController是一个用于控制动画的类。它可以控制动画的开始、停止、反转、重置等操作,并且可以设置动画的持续时间、曲线等属性。

AnimationController 通常在 initState 方法中初始化,在dispose中释放动画

使用AnimationController需要先创建一个实例,然后设置动画的持续时间、曲线等属性,最后通过调用forward()方法来启动动画。在动画运行过程中,可以通过调用reverse()方法来反转动画,通过调用stop()方法来停止动画,通过调用reset()方法来重置动画。

AnimationController还可以添加监听器,用于监听动画的状态变化。例如,可以通过添加addListener()方法来监听动画的值变化,从而更新UI界面。通过添加addStatusListener来监听动画的状态

// 单个 AnimationController 的时候使用 SingleTickerProviderStateMixin,多个 AnimationController 使用 TickerProviderStateMixin。
class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  double size = 100;
  // 定义动画控制器对象
  late AnimationController _controller;

  // AnimationController 通常在 initState 方法中初始化
  
  void initState() {
    // TODO: implement initState
    super.initState();
    // vsync 用于防止屏幕外动画消耗不必要的资源
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );

    // 监听动画帧的变化,在每一帧中调用setState来更新UI,AnimationController 的值默认是 0 到 1
    _controller.addListener(() {
      setState(() {
        // 使size从100到200
        size = 100 + 100 * _controller.value;
      });
    });
    
    //  监听动画的状态,当动画正序完成后反向执行动画
    _controller.addStatusListener((status) {
      // 动画状态status的值有:dismissed(动画停止在开始处)、forward(正向运行)、reverse(反向运行)、completed(动画停止在结束处)
      if (status == AnimationStatus.completed) {
        _controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        _controller.forward();
      }
    });
  }

  
  void dispose() {
    super.dispose();
    //释放动画
    _controller.dispose();
  }

  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
      onTap: () {
        // 启动动画
        _controller.forward();
      },
      child: Container(
        width: size,
        height: size,
        color: Colors.blue,
        alignment: Alignment.center, // 设置文字居中
        child: const Text("点击变大"),
      ),
    ));
  }
}

在这里插入图片描述

Tween

Flutter中的Tween是用于在动画中定义起始值和结束值之间的插值计算的类。它可以将一个范围内的值映射到另一个范围内的值,从而实现动画效果

上面的案例可以修改为

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  double size = 100;
  // 定义动画控制器对象
  late AnimationController _controller;
  // 定义一个动画对象
  late Animation _animation;

  // AnimationController 通常在 initState 方法中初始化
  
  void initState() {
    // TODO: implement initState
    super.initState();
    // vsync 用于防止屏幕外动画消耗不必要的资源
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );

    final Tween tween = Tween(begin: 100.0, end: 200.0);
    _animation = tween.animate(_controller);
    _animation.addListener(() {
      setState(() {
        size = _animation.value;
      });
    });
  }

  
  void dispose() {
    super.dispose();
    //释放动画
    _controller.dispose();
  }

  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
      onTap: () {
        // 启动动画
        _controller.forward();
      },
      child: Container(
        width: size,
        height: size,
        color: Colors.blue,
        alignment: Alignment.center, // 设置文字居中
        child: const Text("点击变大"),
      ),
    ));
  }
}

同理也可以改变颜色

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  Color _color = Colors.blue;
  // 定义动画控制器对象
  late AnimationController _controller;
  // 定义一个动画对象
  late Animation _animation;

  // AnimationController 通常在 initState 方法中初始化
  
  void initState() {
    // TODO: implement initState
    super.initState();
    // vsync 用于防止屏幕外动画消耗不必要的资源
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );

    final Tween tween = ColorTween(begin: Colors.blue, end: Colors.red);
    _animation = tween.animate(_controller);
    _animation.addListener(() {
      setState(() {
        _color = _animation.value;
      });
    });
  }

  
  void dispose() {
    super.dispose();
    //释放动画
    _controller.dispose();
  }

  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
      onTap: () {
        // 启动动画
        _controller.forward();
      },
      child: Container(
        width: 100,
        height: 100,
        color: _color,
        alignment: Alignment.center, // 设置文字居中
        child: const Text("点击改变颜色"),
      ),
    ));
  }
}

在这里插入图片描述

Curve

动画中还有一个重要的概念就是 Curve,即动画执行曲线。使动画的效果能够以匀速、加速、减速、抛物线等各种速率变化。

// 使用了 chain 方法将 ColorTween 和 CurveTween 组合起来
  final Animatable<Color?> tween =
      ColorTween(begin: Colors.blue, end: Colors.red)
          .chain(CurveTween(curve: Curves.easeInOut));
  _animation = tween.animate(_controller);
  _animation.addListener(() {
    setState(() {
      _color = _animation.value;
    });
  });

动画组件

Flutter 系统提供了20多个动画组件,这些组件都是基于动画的核心知识实现的。动画组件分为两大类:

  • 隐式动画组件:只需提供给组件动画开始、结束值,组件创建 AnimationController、Curve、Tween,执行动画,释放AnimationController
  • 显式动画组件:需要设置 AnimationController,控制动画的执行,使用显式动画可以完成任何隐式动画的效果,甚至功能更丰富一些,不过你需要管理该动画的 AnimationController 生命周期
  • 显示动画组件和隐式动画组件中各有一个万能的组件,它们是 AnimatedBuilder 和 TweenAnimationBuilder,当系统中不存在我们想要的动画组件时,可以使用这两个组件

隐式动画组件的使用

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  double _opacity = 1.0;
  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
            onTap: () {
              setState(() {
                _opacity = 0;
              });
            },
            child: AnimatedOpacity(
              opacity: _opacity,
              duration: const Duration(seconds: 1),
              child: Container(
                width: 100,
                height: 100,
                color: Colors.blue,
                alignment: Alignment.center, // 设置文字居中
                child: const Text("点击改变颜色"),
              ),
            )));
  }
}

在这里插入图片描述
**TweenAnimationBuilder **
TweenAnimationBuilder 是 Flutter 中的一个动画构建器,可以用于创建一个在两个值之间进行动画的动画组件。使用 TweenAnimationBuilder 需要指定两个值之间的插值器(Tween),以及动画的持续时间和动画结束后的回调函数。

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  // 一开始不能定义null,否则运行会报错
  late ColorTween _tween = ColorTween(begin: Colors.blue, end: Colors.blue);
  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
            onTap: () {
              setState(() {
                _tween = ColorTween(begin: Colors.blue, end: Colors.red);
              });
            },
            child: TweenAnimationBuilder(
              duration: const Duration(seconds: 1),
              tween: _tween,
              builder: (BuildContext context, Color? value, Widget? child) {
                return Container(
                  width: 100,
                  height: 100,
                  color: value,
                  alignment: Alignment.center, // 设置文字居中
                  child: const Text("点击改变颜色"),
                );
              },
            )));
  }
}
class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  //  动画控制器
  late AnimationController _controller;
  // 颜色动画
  late Animation _colorAnimation;
  // 大小动画
  late Animation _sizeAnimation;

  
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 2));
    // 使用AnimationController的drive方法将一个Tween对象与AnimationController关联起来
    _colorAnimation =
        _controller.drive(ColorTween(begin: Colors.blue, end: Colors.red));
    // 使用AnimationController的drive方法将一个Tween对象与AnimationController关联起来
    _sizeAnimation = _controller
        .drive(SizeTween(begin: const Size(100, 50), end: const Size(50, 100)));
    super.initState();
  }

  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Center(
        //创建一个手势识别器
        child: GestureDetector(
            onTap: () {
              setState(() {
                // 开始动画
                _controller.forward();
              });
            },
            child: AnimatedBuilder(
                animation: _controller,
                builder: (context, widget) {
                  return Container(
                    width: _sizeAnimation.value.width,
                    height: _sizeAnimation.value.height,
                    color: _colorAnimation.value,
                    alignment: Alignment.center, // 设置文字居中
                    child: const Text("点击改变颜色"),
                  );
                })));
  }
}

在这里插入图片描述

列表动画

AnimatedList提供了一种简单的方式使列表数据发生变化时加入过渡动画

AnimatedList主要属性如下表。

属性说明
itemBuilder一个函数,列表的每一个索引会调用,这个函数有一个animation参数,可以设置成任何一个动画
initialItemCountitem的个数
scrollDirection滚动方向,默认垂直
controllerscroll控制器

列表数据的插入和删除有进出场动画需要调用AnimatedListState指定的方法,只删除原数据并调用setState方法是没有动画效果的

class _YcHomeBodyState extends State<YcHomeBody>
    with SingleTickerProviderStateMixin {
  // 定义一个全局的key来管理AnimatedListState对象,并将其传递给AnimatedList构造函数
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
  // 定义列表
  final List<String> _itemList = ["item 1", "item 2", "item 3"];

  // 新增
  void addItem() {
    _itemList.add('item ${_itemList.length + 1}');
    _listKey.currentState?.insertItem(_itemList.length - 1);
  }

  // 删除
  void removeItem() {
    // 删除操作要注意,要先删除列表中的数据在删除AnimatedListState的状态
    // 并且关于index下标的操作,要放在删除操作之前,不然会导致删除时下标错误报错
    int index = _itemList.length - 1;
    String title = _itemList[index];
    _itemList.removeAt(index);
    _listKey.currentState?.removeItem(
      index,
      (context, animation) => SlideTransition(
        position: animation.drive(CurveTween(curve: Curves.easeIn)).drive(
            Tween<Offset>(begin: const Offset(1, 1), end: const Offset(0, 1))),
        child: Card(
          child: ListTile(
            title: Text(title),
          ),
        ),
      ),
    );
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(onPressed: addItem, child: const Text('增加')),
            ElevatedButton(onPressed: removeItem, child: const Text('减少')),
          ],
        ),
        // AnimatedList需要有高度
        Expanded(
            child: AnimatedList(
                key: _listKey,
                initialItemCount: _itemList.length, // item的个数
                itemBuilder: (context, index, animation) {
                  // 为每一个item设置动画,将曲线动画和平移动画结合在一起
                  return SlideTransition(
                    // 动画对象,用于控制子组件的平移动画
                    position: animation
                        .drive(CurveTween(curve: Curves.easeIn))
                        .drive(Tween<Offset>(
                            begin: const Offset(1, 1),
                            end: const Offset(0, 1))),
                    child: Card(
                      child: ListTile(
                        title: Text(_itemList[index]),
                      ),
                    ),
                  );
                }))
      ],
    );
  }
}

这个东西挺难搞的,出了不少问题。删除时一点要注意:

  • 删除操作要注意,要先删除列表中的数据在删除AnimatedListState的状态
  • 并且关于index下标的操作,要放在删除操作之前,不然会导致删除时下标错误报错

关于新增时简单,删除时复杂我查到的解释是:

在AnimatedList中,新增操作只需要添加数据到列表中并调用AnimatedListState的insertItem方法即可,AnimatedListState会自动处理动画效果。
但是删除操作需要手动处理动画效果,因为AnimatedListState无法自动处理删除动画。因此,需要手动调用AnimatedListState的removeItem方法,并在其中指定删除动画的实现方式。

在这里插入图片描述

Hero

Hero用于在两个页面之间实现平滑的过渡效果。它可以将一个widget从一个页面转换到另一个页面,同时保持其外观和位置不
变。
Hero动画通常用于在两个页面之间传递图像或其他媒体内容时,可以使用户感觉到这些内容在两个页面之间平滑地移动。

class _YcHomeBodyState extends State<YcHomeBody> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const SecondPage()),
          );
        },
        child: Hero(
          tag: 'imageHero',
          child: Image.network(
              'https://scpic3.chinaz.net/files/default/imgs/2023-06-07/f84b7dd1b1e82805_s_w285.jpg'),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  const SecondPage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Hero(
          tag: 'imageHero',
          child: Image.network(
              'https://scpic3.chinaz.net/files/default/imgs/2023-06-07/f84b7dd1b1e82805_s_w285.jpg'),
        ),
      ),
    );
  }
}

在这里插入图片描述

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

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

相关文章

深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环

深入理解Qt多线程编程&#xff1a;QThread、QTimer与QAudioOutput的内在联系__QObject的主线程的事件循环 1. Qt多线程编程的基础1.1 QObject和线程&#xff08;QObject and Threads&#xff09;1.2 QThread的使用和理解&#xff08;Understanding and Using QThread&#xff0…

ubuntu下安装transition_amr_parser

ubuntu下安装transition_amr_parser transition_amr_parser是IBM公司开源的AMR paraing和AMR text-to-generation工具&#xff0c;在NLP领域中经常会用到&#xff0c;但是这个安装过程中可能会存在很多坑&#xff0c;transition_amr_parser的github主页安装教程不清晰&#xf…

探秘美颜SDK的动态贴纸的技术原理

美颜SDK作为美颜相机的重要组成部分&#xff0c;其动态贴纸技术也是很多用户喜爱的功能之一。本文将探秘美颜SDK的动态贴纸技术&#xff0c;从技术原理、应用场景和未来发展等方面进行分析。 一、技术原理 **1. 人脸识别技术。**在添加动态贴纸时&#xff0c;第一步要做的肯定…

图的导航 - 最短路径算法

一个 恋爱关系图 胡图图love:98于小美 胡图图love:48何壮壮 胡图图love:99小怪 于小美love:10张帅子 何壮壮love:45张帅子 小怪love:100张帅子 胡图图到张帅子的最短路径 确定不是恋爱路径? 算法实现 先看猛料再看是否实现思路 // 定义深度优先搜索状态 struct DepthFirs…

【Android】WMS(六)Surface的创建和操作

Surface的创建流程 在Android系统中每个Activity都有一个独立的画布&#xff08;在应用侧称为Surface,在SurfaceFlinger侧称为Layer&#xff09;&#xff0c; 无论这个Activity安排了多么复杂的view结构&#xff0c;它们最终都是被画在了所属Activity的这块画布上。 1.Surfac…

618数码好物全推荐,几款科技感满满的数码好物分享

6月18日将迎来一年一度的618狂欢购物节&#xff0c;这可谓是一场精彩绝伦的购物盛宴。每年都有诸多品牌参与其中&#xff0c;我们不仅需要应对复杂的折扣&#xff0c;还需要面对眼花缭乱的产品&#xff0c;这让我们不可避免地陷入了“选择困难症”的困扰中。为了让大家在今年61…

【Android】手持设备规格参数

系列文章 【Android】手持设备规格参数 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/130604517 【H5】avalon前端数据双向绑定 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/131067187 【H5】安卓自动更新方案&…

天空卫士在中国数据安全软件市场位列前五

IDC-中国数据安全软件市场份额&#xff0c;2022 数字经济迅速崛起 中央网信办5月份发布的《数字中国发展报告(2022年)》显示&#xff0c;2022年&#xff0c;我国数字经济规模达50.2万亿元&#xff0c;总量稳居世界第二&#xff0c;同比名义增长10.3%&#xff0c;占国内生产总…

C#,码海拾贝(39)——求解“对称正定方程组”的“共轭梯度法”之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> /…

vue3 script setup 获取父组件函数与参数方法

<script setup>真的可以说是一种非常方便的开发方式了 但没有直接性的setup 拿取父组件的参数和函数就会有点问题 其实vue官方给我提供了defineProps和defineEmits这两个方法是官方提供 不需要引入 直接用就好了 例如这里 我们给子组件传了三个参数 :imgSrc“user.images…

scrcpy 快捷键

可以使用键盘和鼠标在 scrcpy 窗口上执行操作 快捷方式。 在下面的列表中&#xff0c;是快捷方式修饰符。默认情况下&#xff0c;它是 &#xff08;左&#xff09;或&#xff08;左&#xff09;。MODAltSuper 可以使用 进行更改。可能的键是 、 、 和 。例如&#xff1a;–sh…

湖南大学OS-2019期末考试解析

【特别注意】 答案来源于wolf以及网络 是我在备考时自己做的&#xff0c;仅供参考&#xff0c;若有不同的地方欢迎讨论。 【试卷评析】 这张卷子有点老了&#xff0c;部分题目可能有用。如果仔细研究应该会有所收获。 【试卷与答案】 一、选择题&#xff08;15%&#xff…

6、JS-AJAX

6.3、AJAX 6.3.1、AJAX概述 传统的web交互是用户触发一个http请求服务器&#xff0c;然后服务器收到之后&#xff0c;在做出响应到用户&#xff0c;并且返回一个新的页面&#xff0c;每当服务器处理客户端提交的请求时&#xff0c;客户都只能空闲等待&#xff0c;并且哪怕只是…

制作一个电商数据可视化大屏无从下手?看这篇!

01 啥叫可视化大屏&#xff1f; 从字面意思就能看出来&#xff0c;可视化大屏就是有个大屏幕。可视化体现在里面的数据都成了图形和图标&#xff0c; 但是静止的图像也不能完全表现出多报表的结果&#xff0c;可视化大屏是将数据通过图形化、可视化的方式展现在大屏幕上的一种…

【深度学习】BERT变种—百度ERNIE 2.0

ERNIE 2.0 提出了一种持续学习的预训练框架&#xff1a;预训练使用了7种任务&#xff0c;而不是一两种简单的任务。不断引入新的预训练任务&#xff0c;让模型可以持续性地学习不同的预训练任务&#xff0c;并且不会遗忘先前学习的知识&#xff0c;以此让模型能够获得更为全面的…

让小白也能看懂,ChatGPT入门级科普“十问十答”

由于现在GPT火热&#xff0c;360老板已经开始总动员. 白领的日常工作肯定是要发生颠覆性变化的。下面我们就通过自问自答的方式带领小白用户了解一下ChatGPT. 1、ChatGPT到底是什么&#xff1f; ChatGPT 是一个由美国人工智能公司 OpenAI 开发的自然语言处理&#xff08;NLP&…

vue Electron ArcGis 桌面应用 Sqllite3 node-grp:老旧项目的起死回生

最近接收了一个三四年前做的项目。主要技术栈就是vue2electronsqllite3node-gyp。看到这个技术栈&#xff0c;基本可以知道感知这个项目的关键词&#xff1a;vue、Gis地图、本地数据库、桌面客户端。顿时深感亚历山大。 不多说&#xff0c;开干。 第一步&#xff0c;查看项目…

Qemu搭建ARM Vexpress开发环境

Qemu搭建ARM Vexpress开发环境 文章目录 Qemu搭建ARM Vexpress开发环境Qemu简介QEMU安装前的准备工作QEMU 安装的两种方式通过网络在线安装源码编译安装源码获取QEMU依赖库安装编译安装 命令选项qemu的标准选项qemu显示选项网络属性相关选项kvm的网络模型 Ubuntu 双网卡&#x…

阿里高级工程师纯手打造的Spring Cloud Alibaba微服务全彩手册,限时分享

Spring Cloud Alibaba 是阿里巴巴提供的微服务开发一站式解决方案&#xff0c;是阿里巴巴开源中间件与 Spring Cloud 体系的融合。 Springcloud 和 Srpingcloud Alibaba 区别&#xff1f; SpringCloud&#xff1a; 部分组件停止维护和更新&#xff0c;给开发带来不便;SpringC…

msvcr120.dll丢失怎样修复,快速修复msvcr120.dll的方法分享

msvcr120.dll是Microsoft Visual C Redistributable for Visual Studio 2013的一个组件&#xff0c;是一个动态链接库文件。它包含了许多函数和程序&#xff0c;可以被其他程序调用&#xff0c;这些程序使用了Visual C 2013运行时库。在Windows操作系统中&#xff0c;许多软件和…