Flutter动画详解第二篇之显式动画(Explicit Animations)

目录

前言

一、定义

1.AnimationController

1.常用属性

1. value

2. status

3. duration

2.常用方法

1.forward

2.reverse

3.repeat

4.stop

5. reset

6. animateTo(double target, {Duration? duration, Curve curve = Curves.linear})

7.animateBack(double target, {Duration? duration, Curve curve = Curves.linear})

8. addListener(VoidCallback listener)

10.addStatusListener(AnimationStatusListener listener)

11. removeStatusListener(AnimationStatusListener listener)

        移除状态监听器。

2.Animation

3.Tween

4.Listeners

5.Builders

二、常见的显示动画组件

1.RotationTransition       

2.FadeTransition

3.ScaleTransition

4.SlideTransition

三、自定义显式动画

四、参考文章


前言

    上一篇文章介绍了Flutter中的隐式动画的用法。

    我们会发现隐式动画使用起来非常的方便,我们只需要设置动画的旧值变化之后的值,Flutter会帮助我们完整动画的中间过程。Flutter中隐式动画的实现是全自动的。

     今天我们介绍下Flutter中的显式动画。

一、定义

        在Flutter中,显式动画(Explicit Animations)指的是那些需要你手动控制动画过程的动画。显式动画提供了更多的控制权,但也需要更多的代码和管理。显式动画通常涉及到以下几个核心组件:

  1. AnimationController
  2. Animation
  3. Tween
  4. Listeners
  5. Builders

            核心组件的详解如下:

1.AnimationController

        AnimationController是 Flutter 动画框架的核心部分之一,用于控制动画的播放、停止、前进、倒退等。它提供了丰富的 API 来管理和控制动画的行为。下面是 AnimationController的一些常用 API 及其解释:

1.常用属性

1. value

        当前动画的值。可以是 `double` 类型,表示动画当前的进度。

double currentValue = controller.value;

2. status

        当前动画的状态,是AnimationStatus枚举类型,可能的值有dismissed、forward、reverse 和 completed。

AnimationStatus currentStatus = controller.status;

3. duration

        动画的时长。

controller.duration = Duration(seconds: 2);

4. upperBound和 lowerBound

       动画的范围。

controller.upperBound = 1.0;
controller.lowerBound = 0.0;

2.常用方法

1.forward

        动画正向执行,从lowerBound到upperBound。

 controller.forward();

2.reverse

        动画反向执行,从upperBound到lowerBound

controller.reverse();

3.repeat

        重复执行动画,可以指定周期和是否反向。

 controller.repeat(reverse: true);

4.stop

        停止动画。

controller.stop();

5. reset

        重置动画到 `lowerBound`,并停止动画。

controller.reset();

6. animateTo(double target, {Duration? duration, Curve curve = Curves.linear})

        动画执行到指定值。

   controller.animateTo(0.5, duration: Duration(seconds: 1), curve: Curves.easeInOut);

7.animateBack(double target, {Duration? duration, Curve curve = Curves.linear})

        动画反向执行到指定值。

controller.animateBack(0.0, duration: Duration(seconds: 1), curve: Curves.easeInOut);

8. addListener(VoidCallback listener)

        添加监听器,每次动画值改变时调用。

controller.addListener(() {
     setState(() {
       // 更新UI
     });
   });

9. removeListener(VoidCallback listener)

        移除监听器。

controller.removeListener(listener);

10.addStatusListener(AnimationStatusListener listener)

        添加状态监听器,动画状态改变时调用。

controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        // 动画完成
      }
    });

11. removeStatusListener(AnimationStatusListener listener)
        移除状态监听器。

  controller.removeStatusListener(listener);

2.Animation

        在 Flutter 中,显式动画需要开发者手动管理动画的每个步骤,其中 Animation 类是核心组件之一。Animation 类本身是一个抽象类,它定义了动画的当前值和状态,并且可以被监听以响应动画的变化。通过 Animation 类,开发者可以访问动画的值并将其应用到 UI 元素上。

        在实际做动画的过程中,我们会用到各种各样的Animation。例如我们做缩放动画的时候,Animation的类型为double类型,渐变动画的时候,Animation可以表示颜色的动画,平移动画的时候,Animation可以表示平移的大小。

3.Tween

        定义动画的开始和结束值。常见的有 Tween<double>、ColorTween 等。

4.Listeners

        通过 addListener 和 addStatusListener 可以监听动画的每一帧和动画状态的变化。

5.Builders

        通过 AnimatedBuilder 或 CustomPainter 等将动画值应用到UI上。

二、常见的显示动画组件

        显示动画都以Transition结尾。常见的显示动画有RotateAnimation动画、FadeTransition、ScaleTransition、SlideTransition、AnimatedIcon。在显示动画中,我们通过AnimatedController控制动画的开始、暂停、重置、跳转、倒播等。

1.RotationTransition       

        RotationTransition主要用来做旋转动画。

        我们以下面的效果为例,看看如何使用RotationTransition动画。

        图1.RotationTransition动画

        我们要做一个不停旋转的FlutterLogo。

        首先我们设置FlutterLogo的大小为60。

        我们要做一个不停旋转的显式动画,因此我们需要再FlutterLogo的外面使用RotationTransition包裹起来。

代码如下:

  @overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('RotateAnimation动画'),),body: Center(child: RotationTransition(turns: controller,child: const FlutterLogo(size: 60,),),),);}

        我们看一下RotatinTransition的定义:

  const RotationTransition({super.key,required Animation<double> turns,super.alignment = Alignment.center,super.filterQuality,super.child,}) : super(animation: turns, onTransform: _handleTurnsMatrix);

        这里必须要传递AnimationController对象。因此我们在定义AnimationController。

// 定义AnimationController
late AnimationController controller;

           为了让程序和手机的刷新频率保持一致,我们的Stateful后面要实现SingleTickerProviderStateMixin。

        代码如下:

class _RotateAnimationDemosState extends State<RotateAnimationDemos> with SingleTickerProviderStateMixin{// 定义AnimationControllerlate AnimationController controller;
}

        然后我们Widget的初始化方法中,初始化我们的AnimationController。

        这里我们设置下动画的时长,vsync参数传this。表示当前app和手机刷新的频率保持一致。

  //初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 3), vsync: this);}

            OK.到这里之后,完整的代码如下:

import 'package:flutter/material.dart';class RotateAnimationDemos extends StatefulWidget {const RotateAnimationDemos({super.key});@overrideState<RotateAnimationDemos> createState() => _RotateAnimationDemosState();
}class _RotateAnimationDemosState extends State<RotateAnimationDemos>with SingleTickerProviderStateMixin {// 定义AnimationControllerlate AnimationController controller;//初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller =AnimationController(duration: const Duration(seconds: 3), vsync: this);}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('RotateAnimation动画'),),body: Center(child: RotationTransition(turns: controller,child: const FlutterLogo(size: 60,),),),);}
}

        运行代码之后,页面加载出来了,但是FlutterLogo没有转起来。

        因为显式动画是手动控制动画的播放,因此我们还需要手动调用下AnimationController的repeat方法。

  //初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 3), vsync: this)..repeat();}

        再次运行,就发现FlutterLogo旋转起来了。

完整代码如下:

import 'package:flutter/material.dart';class RotateAnimationDemos extends StatefulWidget {const RotateAnimationDemos({super.key});@overrideState<RotateAnimationDemos> createState() => _RotateAnimationDemosState();
}class _RotateAnimationDemosState extends State<RotateAnimationDemos>with SingleTickerProviderStateMixin {// 定义AnimationControllerlate AnimationController controller;//初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 3), vsync: this)..repeat();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('RotateAnimation动画'),),body: Center(child: RotationTransition(turns: controller,child: const FlutterLogo(size: 60,),),),);}
}

        上述调用了AnimationController的repeat方法,AnimationController还提供了forward、reverse、stop、reset等常用方法,它们的含义如下:

  1. forward:动画仅执行一次
  2. reverse:动画倒序执行一次
  3. stop:动画停止
  4. reset:动画重置
  5. repeat:重复的执行动画

        如果感兴趣,可以逐个调用这些方法看看效果。

2.FadeTransition

        FadeTransition用于制作透明度动画。

        FadeTransition和RotationTransition的用法基本差不多。

        下面的例子中,展示了使用FadeTransition制作动画的过程。

        图2.FadeTransition动画

        完整代码如下:

import 'package:flutter/material.dart';class FadeAnimationDemos extends StatefulWidget {const FadeAnimationDemos({super.key});@overrideState<FadeAnimationDemos> createState() => _FadeAnimationDemosState();
}class _FadeAnimationDemosState extends State<FadeAnimationDemos> with SingleTickerProviderStateMixin{// 定义AnimationControllerlate AnimationController controller;//初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 1),vsync: this,lowerBound: 0.1,upperBound: 1.0,)..repeat();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('FadeTransition动画'),),body: Center(child:FadeTransition(opacity: controller,child: const FlutterLogo(size: 200,),),),);}
}

3.ScaleTransition

        ScaleTransition用于制作缩放动画,依然可以使用AnimationController更加精准的控制动画的细节。

        图3.缩放动画

        完整代码如下:

import 'package:flutter/material.dart';class ScaleTransitionDemos extends StatefulWidget {const ScaleTransitionDemos({super.key});@overrideState<ScaleTransitionDemos> createState() => _ScaleTransitionDemosState();
}class _ScaleTransitionDemosState extends State<ScaleTransitionDemos> with SingleTickerProviderStateMixin{// 定义AnimationControllerlate AnimationController controller;//初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 1),vsync: this,lowerBound: 0.1,upperBound: 1.0,)..repeat();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('ScaleTransition动画'),),body: Center(child:ScaleTransition(scale: controller,child: Container(width: 100,height: 100,color: Colors.deepPurpleAccent,),),),);}
}

4.SlideTransition

        SlideTransition用于做平移动画。

        下图是使用SlideTransition制作的平移动画。

图4.SlideTransition动画

        完整代码如下:

import 'package:flutter/material.dart';class SlideTransitionDemos extends StatefulWidget {const SlideTransitionDemos({super.key});@overrideState<SlideTransitionDemos> createState() => _SlideTransitionDemosState();
}class _SlideTransitionDemosState extends State<SlideTransitionDemos> with SingleTickerProviderStateMixin{// 定义AnimationControllerlate AnimationController controller;//初始化 AnimationController@overridevoid initState() {super.initState();//vsync: 让程序和手机的刷新频率统一controller = AnimationController(duration: const Duration(seconds: 1),vsync: this,lowerBound: 0.1,upperBound: 1.0,)..repeat();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('SlideTransition动画'),),body: Center(child:SlideTransition(position: controller.drive(Tween(begin: const Offset(0, 0), end: const Offset(0.5, 0))),child: const FlutterLogo(size: 200,),),),);}
}

        我们还可以使用AnimationController的drive方法修改动画的初始值。

        例如在下面的缩放动画代码中,开始的时候,长度和宽度都是从0.5倍开始,2倍结束。

        部分代码如下:

Center(child:ScaleTransition(scale: controller.drive(Tween(begin: 0.5, end: 2.0)),child: Container(width: 100,height: 100,color: Colors.deepPurpleAccent,),),)

        还可以调用AnimationController的chain方法叠加动画的曲线。

三、自定义显式动画

        这里我们看一下如何自定义显式动画。

        例如我们这里有一个透明度为0.9的Container组件,代码如下:

import 'package:flutter/material.dart';class CustomExplicitPage extends StatefulWidget {const CustomExplicitPage({super.key});@overrideState<CustomExplicitPage> createState() => _CustomExplicitPageState();
}class _CustomExplicitPageState extends State<CustomExplicitPage> with SingleTickerProviderStateMixin {late AnimationController _controller;@overridevoid initState() {super.initState();_controller = AnimationController(vsync: this);}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('自定义显示动画'),),body: Center(child: Opacity(opacity: 0.9,child: Container(alignment: Alignment.center,color: Colors.deepPurpleAccent,width: 250,height: 250,child: const Text('Hi',style: TextStyle(fontSize: 24),),),),),);}
}

        我们看下如何使用AnimatedBuilder实现自定义显式动画。

        首先我们把需要制作动画的Widget的外层包裹一个AnimatedBuilder。builder函数内部返回要操作的Widget,把AnimatedController传给AnimatedBuilder的animation属性。

        部分代码如下:

Center(child: AnimatedBuilder(animation: _controller,builder: (BuildContext context, Widget? child) {return Opacity(opacity: 0.9,child: Container(alignment: Alignment.center,color: Colors.deepPurpleAccent,width: 250,height: 250,child: const Text('Hi',style: TextStyle(fontSize: 24),),),);},),)

             然后调用AnimationController的repeat方法,一个自定义的显式动画就实现了。

        完整代码如下:

import 'package:flutter/material.dart';class CustomExplicitPage extends StatefulWidget {const CustomExplicitPage({super.key});@overrideState<CustomExplicitPage> createState() => _CustomExplicitPageState();
}class _CustomExplicitPageState extends State<CustomExplicitPage> with SingleTickerProviderStateMixin {late AnimationController _controller;@overridevoid initState() {super.initState();_controller = AnimationController(vsync: this,duration: const Duration(seconds: 2))..repeat();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('自定义显示动画'),),body: Center(child: AnimatedBuilder(animation: _controller,builder: (BuildContext context, Widget? child) {return Opacity(opacity: _controller.value,child: Container(alignment: Alignment.center,color: Colors.deepPurpleAccent,width: 250,height: 250,child: const Text('Hi',style: TextStyle(fontSize: 24),),),);},),),);}
}

        完整的效果如下:

        图5.自定义显式动画

四、参考文章

1.教程 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter

    

        

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

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

相关文章

Qt 快速保存配置的方法

Qt 快速保存配置的方法 一、概述二、代码1. QFileHelper.cpp2. QSettingHelper.cpp 三、使用 一、概述 这里分享一下&#xff0c;Qt界面开发时&#xff0c;快速保存界面上一些参数配置的方法。 因为我在做实验的时候&#xff0c;界面上可能涉及到很多参数的配置&#xff0c;我…

鼠标的发明和鼠标“变形记”

注&#xff1a;机翻&#xff0c;未校对。 Who Invented the Computer Mouse? 谁发明了电脑鼠标&#xff1f; It was technology visionary and inventor Douglas Engelbart (January 30, 1925 – July 2, 2013) who revolutionized the way computers worked, turning it fr…

【数据结构】--- 顺序表

目录 前言&#xff1a; 顺序表 动态顺序表的实现 代码总览&#xff1a; 前言&#xff1a; 数据结构是由“数据”和“结构”两词组合而来。 什么是数据&#xff1f; 常见的数值1、2、3、4.....、教务系统⾥保存的⽤⼾信息&#xff08;姓名、性别、年龄、…

Kafka Producer之ACKS应答机制

文章目录 1. 应答机制2. 等级03. 等级14. 等级all5. 设置等级6. ISR 1. 应答机制 异步发送的效率高&#xff0c;但是不安全&#xff0c;同步发送安全&#xff0c;但是效率低。 无论哪一种&#xff0c;有一个关键的步骤叫做回调&#xff0c;也就是ACKS应答机制。 其中ACKS也分…

Qt QProcess 进程间通信读写数据通信

本文介绍了如何使用Qt的QProcess 进行程序开发&#xff0c;包括启动进程间通信、设置环境变量、通用方法&#xff1b;方便在日常开发中使用&#xff1b; 1.使用Qt进行程序开发&#xff0c;可以通过QProcess类用于启动外部程序并与其进行通信.&#xff1b; 进程A&#xff08;…

CentOS 7 安装MySQL 5.7.30

CentOS 7 安装MySQL卸载&#xff08;离线安装&#xff09; 安装配置MySQL之前先查询是否存在&#xff0c;如存在先卸载再安装 rpm -qa|grep -i mysql rpm -qa|grep -i mariadb rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x86_64如下命令找到直接 rm -rf 删除&#xff08;删除…

代理IP服务中的代理池大小有何影响?

在当今数字化时代&#xff0c;网络爬虫已经成为获取各类信息必不可少的工具。在大规模数据抓取中&#xff0c;使用单一 IP 地址或同一 IP 代理往往会面临抓取可靠性降低、地理位置受限、请求次数受限等一系列问题。为了克服这些问题&#xff0c;构建代理池成为一种有效的解决方…

Java基础笔记(面试题)

一、Tomcat中为什么要使用自定义类加载器 Tomcat中可以放多个Java项目的jar文件&#xff0c;如果每个jar文件中都有一个User的类&#xff0c;那么User类在没有自定义类加载器的情况下是只能加载一次&#xff1b;想要加载多次&#xff0c;只能自定义类加载器 二、JDK、JRE、JVM…

【leetcode】 字符串相乘(大数相乘、相加)

记录一下大数相乘相加方法&#xff1a; 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: nu…

基于嵌入式Linux的高性能车载娱乐系统设计与实现 —— 融合Qt、FFmpeg和CAN总线技术

随着汽车智能化的发展&#xff0c;车载娱乐系统已成为现代汽车的标配。本文介绍了一个基于Linux的车载娱乐系统的设计与实现过程。该系统集成了音视频娱乐、导航、车辆信息显示等功能&#xff0c;旨在提供安全、便捷、丰富的驾驶体验。 1. 项目概述 随着汽车智能化的发展&…

Java对象转换为JSON字符串

0 写在前面 业务中有很多场景需要 把一个带有数据的 Java对象/Java集合转换为JSON 存入数据库中。 在需要的时候还需要吧和这个JSON字符串拿出来再次转换成Java对象/集合 1 Java对象与JSON字符串互转 引入依赖: <dependency><groupId>com.alibaba</groupId&…

【5G Sub-6GHz模块】专为IoT/eMBB应用而设计的RG520NNA、RG520FEB、RG530FNA、RG500LEU 5G模组

推出全新的5G系列模组&#xff1a; RG520NNADB-M28-SGASA RG520NNADA-M20-SGASA RG520FEBDE-M28-TA0AA RG530FNAEA-M28-SGASA RG530FNAEA-M28-TA0AA RG500LEUAA-M28-TA0AA ——明佳达 1、5G RG520N 系列——专为IoT/eMBB应用而设计的LGA封装模块 RG520N 系列是一款专为 IoT…

内容安全(深度行为检测技术、IPS、AV、入侵检测方法)

1、深度行为检测技术 深度行为检测技术&#xff1a;是一种基于深度学习和机器学习的技术&#xff0c;它通过分析用户在网络中的行为模式&#xff0c;识别异常或潜在威胁行为&#xff0c;从而保护网络安全和内容安全 分类&#xff1a; 深度包检测技术&#xff08;Deep Packet…

【Redis7】高阶篇

1 Redis单线程 VS 多线程(入门篇) 1.1 面试题 redis到底是单线程还是多线程&#xff1f; IO多路复用听说过吗&#xff1f; redis为什么快&#xff1f; 1.2 Redis为什么选择单线程&#xff1f; 1.2.1 是什么 这种问法其实并不严谨&#xff0c;为啥这么说呢? Redis的版本…

通用图形处理器设计GPGPU基础与架构(四)

一、前言 本文将介绍GPGPU中线程束的调度方案、记分牌方案和线程块的分配与调度方案。 二、线程束调度 在计算机中有很多资源&#xff0c;既可以是虚拟的计算资源&#xff0c;如线程、进程或数据流&#xff0c;也可以是硬件资源&#xff0c;如处理器、网络连接或 ALU 单元。调…

【DGL系列】DGLGraph.out_edges简介

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 函数说明 用法示例 示例 1: 获取所有边的源节点和目标节点 示例 2: 获取特定节点的出边 示例 3: 获取所有边的边ID 示例 4: 获取所有信息&a…

PyTorch张量索引

文章目录 1、简介1.1、基本概念1.2、索引类型1.3、数据准备1.4、技术摘要⭐ 2、简单行、列索引3、列表索引4、范围索引5、布尔索引6、多维索引 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#…

未来的社交标杆:如何通过AI让Facebook更加智能化?

在当今信息爆炸的时代&#xff0c;社交媒体平台的智能化已成为提高用户体验和互动质量的关键因素。Facebook&#xff0c;作为全球最大的社交平台之一&#xff0c;通过人工智能&#xff08;AI&#xff09;的广泛应用&#xff0c;正不断推进其智能化进程。本文将探讨Facebook如何…

Postman安装使用教程(详解)

目录 一、Postman是什么 二、安装系统要求 三、下载Postman 四、注册和登录Postman 五、创建工作空间 六、创建请求 一、Postman是什么 在安装之前&#xff0c;让我们先来简单了解一下Postman。Postman是一个流行的API开发工具&#xff0c;它提供了友好的用户界面用于发送…

web安全之跨站脚本攻击xss

定义: 后果 比如黑客可以通过恶意代码,拿到用户的cookie就可以去登陆了 分类 存储型 攻击者把恶意脚本存储在目标网站的数据库中(没有过滤直接保存)&#xff0c;当用户访问这个页面时&#xff0c;恶意脚本会从数据库中被读取并在用户浏览器中执行。比如在那些允许用户评论的…