Flutter进阶-动画详解

news2024/12/22 6:16:01

目录

动画类别

一、隐式(全自动)动画

二、显式动画(手动控制)

三、其他动画(CustomPainter)

动画类别

Flutter 中有多种类型的动画:

  • 隐式动画:通过更改部件属性自动触发的预定义动画,例如 AnimatedContainerAnimatedOpacity 、AnimatedPadding等等。
  • 显式动画:通过使用 Animation 和 AnimationController 类手动控制动画。
  • 物理动画:基于物理规律的动画,例如 SpringSimulationFrictionSimulation 等等。

一、隐式(全自动)动画

 AnimatedSwitcher(
          duration: const Duration(seconds: 2),
          transitionBuilder: (child, animation) {
            return FadeTransition(
              opacity: animation,
              child: ScaleTransition(
                scale: animation,
                child: child,
              ),
            );
          },
          child: const Text("Hello"),
        )

补间动画(已经确定了第一帧(0.0)和最后一帧(1.0),如果FPS 60 补充中间的58帧)

 TweenAnimationBuilder(
            tween: Tween(begin: 0.0, end: 1.0),
            duration: const Duration(seconds: 5),
            builder: (BuildContext context, Object? value, Widget? child) {
              return Opacity(
                opacity: value as double,
                child: Container(
                  width: 300,
                  height: 300,
                  color: Colors.red[200],
                ),
              );
            }))
TweenAnimationBuilder(
            tween: Tween(begin: 20.0, end: 50.0),
            duration: const Duration(seconds: 5),
            builder: (context,double value, Widget? child) {
              return Container(
                  width: 300,
                  height: 300,
                  color: Colors.red[200],
                  child: Text('Hello', style: TextStyle(fontSize: value)));
            }))

二、显式动画(手动控制)

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))..repeat();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: AnimatedBuilder(
            animation: _controller,
            builder: (BuildContext context, Widget? child) {
              return Opacity(
                  opacity: _controller.value,
                  child: Container(
                    width: 300,
                    height: 300,
                    color: Colors.blue,
                  ));
            }));
  }
}

上面的渐变动画不用经典的显示动画万能控件AnimatedBuilder的话,可以直接使用FadeTransition

 FadeTransition(
                    opacity: _controller,
                    child:
                        Container(width: 200, height: 200, color: Colors.blue),
                  )),

可以无尽旋转的动画

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
      
  late AnimationController _controller;
  bool _loading = false;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: RotationTransition(
              turns: _controller, child: const Icon(Icons.refresh, size: 100)),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            if (_loading) {
              _controller.reset();
            } else {
              _controller.repeat();
            }
            _loading = !_loading;
          },
        ));
  }
}

FadeTransition、ScaleTransition、SlideTransition

控制器串联Tween补间和Curve曲线

ScaleTransition(
             scale: _controller.drive(Tween(begin: 0.5, end:2.0)), child: const Icon(Icons.refresh, size: 100)),
        ),
SlideTransition(
             position: _controller.drive(Tween(begin: Offset(0,0), end:Offset(1,0))), 
// position:Tween(begin: const Offset(0, 0), end: const Offset(1, 0)).animate(_controller),
child: const Icon(Icons.refresh, size: 100)),

 position:Tween(begin: const Offset(0, 0), end: const Offset(1, 0))
                      .chain(CurveTween(curve: Curves.elasticInOut))
                      .animate(_controller),
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {

  late AnimationController _controller;
  final bool _loading = false;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))..repeat(reverse:true);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
          child: Column(children: [
       SlidingBox(
          controller: _controller,
          color: Colors.blue[100]!,
          interval: const Interval(0.0, 0.2),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[300]!,
          interval: const Interval(0.2, 0.4),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[500]!,
          interval: const Interval(0.4, 0.6),
        ),
          SlidingBox(
          controller: _controller,
          color: Colors.blue[700]!,
          interval: const Interval(0.6, 0.8),
        ),
        SlidingBox(
          controller: _controller,
          color: Colors.blue[900]!,
          interval: const Interval(0.8, 1.0),
        ),
      ])),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _controller.forward();
        },
      ),
    );
  }
}

class SlidingBox extends StatelessWidget {
  final AnimationController controller;
  final Color color;
  final Interval interval;

  const SlidingBox(
      {Key? key,
      required this.controller,
      required this.color,
      required this.interval})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
        position: Tween(begin: Offset.zero, end: const Offset(0.2, 0))
            .chain(CurveTween(curve: Curves.bounceOut))
            .chain(CurveTween(curve: interval))
            .animate(controller),
        //CurveTween(curve: const Interval(0.8, 1.0)) 控制动画从最后的1/5时间开始到结束
        child: Container(width: 300, height: 100, color: color));
  }
}

自定义呼吸灯动画 

 

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late AnimationController _expansionController;
  late AnimationController _opacityController;

  @override
  void initState() {
    _expansionController = AnimationController(vsync: this);
    _opacityController = AnimationController(vsync: this);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: FadeTransition(
            opacity: Tween(begin: 1.0, end: 0.5).animate(_opacityController),
            child: AnimatedBuilder(
                animation: _expansionController,
                builder: (BuildContext context, Widget? child) {
                  return Container(
                    height: 200,
                    width: 200,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.blue,
                      gradient: RadialGradient(colors: [
                        Colors.blue[600]!,
                        Colors.blue[100]!,
                      ], stops: [
                        _expansionController.value,
                        _expansionController.value + 0.1
                      ]),
                    ),
                  );
                }),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () async {
            _expansionController.duration = const Duration(seconds: 4);
            _expansionController.forward();
            await Future.delayed(const Duration(seconds: 4));
            _opacityController.duration = const Duration(milliseconds: 1750);
            _opacityController.repeat(reverse: true);
            await Future.delayed(const Duration(seconds: 7));
            _opacityController.reset();
            _expansionController.duration = const Duration(seconds: 8);
            _expansionController.reverse();
          },
        ));
  }
}

三、其他动画(CustomPainter)

直接操作底层的

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  final List<Snowflake> _snowflakes =
      List.generate(100, (index) => Snowflake());

  @override
  void initState() {;
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 4))
          ..repeat();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Container(
            width: double.infinity,
            height: double.infinity,
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [Colors.blue, Colors.lightBlue, Colors.white],
                  stops: [0.0, 0.75, 0.95]),
            ),
            child: AnimatedBuilder(
              animation: _controller,
              builder: (BuildContext context, Widget? child) {
                for (var snow in _snowflakes) {
                  snow.fall();
                }
                return CustomPaint(
                  painter: MyPainter(_snowflakes),
                );
              },
            ),
          ),
        ));
  }
}

class MyPainter extends CustomPainter {
  final List<Snowflake> _snowflakes;
  MyPainter(this._snowflakes);

  @override
  void paint(Canvas canvas, Size size) {
    final whitePaint = Paint()..color = Colors.white;
    canvas.drawCircle(size.center(const Offset(0, 100)), 60.0, whitePaint);
    canvas.drawOval(
        Rect.fromCenter(
            center: size.center(const Offset(0, 260)), width: 230, height: 250),
        whitePaint);
    _snowflakes.forEach((snowflake) {
      canvas.drawCircle(
          Offset(snowflake.x, snowflake.y), snowflake.radius, whitePaint);
    });
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

class Snowflake {
  double x = Random().nextDouble() * 400;
  double y = Random().nextDouble() * 800;
  double radius = Random().nextDouble() * 2 + 2;
  double velocity = Random().nextDouble() * 4 + 2;
  void fall() {
    y += velocity;
    if (y > 800) {
      y = 0;
      x = Random().nextDouble() * 400;
      radius = Random().nextDouble() * 2 + 2;
      velocity = Random().nextDouble() * 4 + 2;
    }
  }
}

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

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

相关文章

什么是cookie

1、cookie是什么 Cookie&#xff0c;有时也用其复数形式Cookies。类型为“小型文本文件”&#xff0c;是某些网站为了辨别用户身份&#xff0c;进行Session跟踪而储存在用户本地终端上的数据&#xff08;通常经过加密&#xff09;&#xff0c;由用户客户端计算机暂时或永久保存…

Python强类型编程

Python是一门强类型的动态类型语言&#xff0c;具体如下特性&#xff1a; 可以动态构造脚本执行、修改函数、对象类型结构、变量类型但不允许类型不匹配的操作 第一个例子体现动态性&#xff1a;用字符串直接执行代码&#xff0c;动态构建了一个函数并执行&#xff0c;甚至给…

力扣744.寻找比目标字母大的最小字符(java暴力查找法,二分查找法)

题目描述&#xff1a; 给你一个字符数组 letters&#xff0c;该数组按非递减顺序排序&#xff0c;以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符&#xff0c;则返回 letters 的第一个字符。 [外链…

岭回归(Ridge)不同alpha值对归回结果的影响

对于有些矩阵&#xff0c;矩阵中某个元素的一个很小的变动&#xff0c;会引起最后计算结果误差很大&#xff0c;这种矩阵称为“病态矩阵”。有些时候不正确的计算方法也会使一个正常的矩阵在运算中表现出病态。对于高斯消去法来说&#xff0c;如果主元&#xff08;即对角线上的…

亚马逊测评:如何有效使用IP和养号设备环境

随着网络科技的崛起&#xff0c;越来越多的本土企业入驻亚马逊电子商务平台上&#xff0c;这导致了对产品评价需求的激增。然而&#xff0c;评价并非随意进行&#xff0c;它需要多方面的资源&#xff0c;并需要密切注意一些重要环节。以下是我分享给大家一些宝贵的知识&#xf…

如何实现敏捷交付中的自动化测试优化

在提及自动化测试的时候&#xff0c;很多人会把工具的使用等同于自动化测试。自动化测试应该是一个策略性的系统化工程&#xff0c;不只有自动化工具。自动化测试要发挥其频繁快速的质量反馈作用&#xff0c;还需要团队从文化和技术上去建设和学习。 提到敏捷交付&#xff0c;…

数据库监控与调优【十二】—— JOIN语句优化

JOIN语句优化-JOIN种类、算法与原理 JOIN的种类 笛卡尔连接&#xff08;cross join&#xff09; -- 举例&#xff1a;通过笛卡尔连接查询两张表的结果集和单查两张表的结果集对比 SELECT count( * ) FROM users a CROSS JOIN orders b; SELECT ( SELECT count( * ) FROM user…

SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 文章目录 前端…

微服务: sleuth和zipkin的用处与zipkin安装使用(下)

目录 0. 上篇传送门: 1. 前言简介 mq安装传送门: 微服务: 01-rabbitmq的应用场景及安装(docker) 1.1 Sleuth是一款分布式跟踪解决方案。 1.2 Zipkin是一个开源的分布式跟踪系统。 2. zipkin安装方式 2.1 windows下安装zipkin: 2.1.0 下载jar包位置 2.1.1 下载后,找…

数值计算例题整理

数值计算 一、误差的来源和分类二、有效数字第一个大题&#xff08;非线性方程组的迭代法&#xff09;第二个大题&#xff08;LU分解&#xff09;第三个大题&#xff08;牛顿插值法&#xff09;第四个大题&#xff08;直线拟合&#xff09; 一、误差的来源和分类 误差是描述数…

Git 原理和使用

Git 安装 Git是开放源代码的代码托管⼯具&#xff0c;最早是在Linux下开发的。开始也只能应⽤于Linux平台&#xff0c;后⾯慢慢的被移植到windows下&#xff0c;现在&#xff0c;Git可以在Linux、Unix、Mac和Windows这⼏⼤平台上正常运⾏了。 Linux-centos 安装git sudo yu…

8.3 PowerBI系列之DAX函数专题-矩阵Matrix中高亮显示最大最小值

需求 用颜色标量年度最大最小值 用颜色标示折线的最大值最小值 实现 在条件格式–规则–基于字段进行计算 度量值 is_max_min var displayed_data calculatetable( addcolumns( summarize(‘订单表’&#xff0c;‘产品表’[商品次级类别]&#xff0c;‘订单表’[订单日…

arcgis栅格影像裁剪--shp

1、打开软件&#xff0c;导入数据&#xff0c;如下&#xff1a; 2、裁剪面形状如下&#xff0c;为shp文件&#xff1a; 3、在arctoolbox中找到"数据管理工具"--"栅格"--"栅格处理"--"裁剪"工具&#xff0c;如下&#xff1a; 4、打开裁…

(ESP32)报错-portTICK_RATE_MS‘ undeclared

&#xff08;ESP32&#xff09;报错-portTICK_RATE_MS undeclared 问题详情ESP- IDF未正确设置 问题详情 报错提示 portTICK_RATE_MS undeclared (first use in this function); did you mean portTICK_PERIOD_MS?具体情况 已经引用相关头文件&#xff0c;并且右键后可以大概…

leetcode 2462. Total Cost to Hire K Workers(雇用 K 名员工的总成本)

每次从 开头candidates个 和 末尾candidates个 工人中选择一个cost最小的。 如果有2个工人cost相同&#xff0c;就选index较小的。 每个工人的cost在数组costs里。 直到雇够k个工人。 问雇k个工人需要多少cost. 思路&#xff1a; 可以考虑用一个优先队列&#xff0c;按cost排…

2023开放原子全球开源峰会——一场开发者的盛宴

文章目录 上午场下午场开发者之夜 #“2023我在开源峰会”特别征文# 2023开放原子全球开源峰会&#xff0c;6月11日-13日在北京盛大召开&#xff0c;开幕第一天正好是周六&#xff0c;没什么事情&#xff0c;一大早就过去了&#xff0c;早晨大概7点出发&#xff0c;公交、地铁一…

Docker Desktop 安装使用教程

一、前言 作为开发人员&#xff0c;在日常开发中&#xff0c;我们需要在本地去启动一些服务&#xff0c;如&#xff1a;redis、MySQL等&#xff0c;就需要去下载这些在本地去启动&#xff0c;操作较为繁琐。此时&#xff0c;我们可以使用Docker Desktop&#xff0c;来搭建我们需…

php+mysql期末作业小项目

目录 1、登录界面 2、注册界面 3、主界面 4、学生表界面 5 、查询学生界面​编辑 6、修改学生信息界面​编辑 7、删除学生信息界面 8、添加学生信息界面 9、后台数据库​编辑 一个简单的php➕mysql项目学生信息管理系统&#xff0c;用于广大学子完成期末作业的参考&…

Android Studio导入flutter项目,运行和调试按钮灰色

描述&#xff1a;用android Studio导入flutter项目&#xff0c;运行和调试按钮无法点击并置灰&#xff0c;显示如下 解决方法&#xff1a;检查是否设置如下内容&#xff1a; 1.是否配置了Android SDK &#xff0c;打开 file > project Structure >project 2.是否配置了F…

【架构】领域驱动设计(DDD)的几种典型架构介绍

文章目录 前言一、专业术语二、架构演变三、限界上下文四、领域驱动设计的四重边界五、整洁分层架构六、六边形架构七、洋葱架构总结 前言 我们生活中都听说了DDD&#xff0c;也了解了DDD&#xff0c;那么怎么将一个新项目从头开始按照DDD的过程进行划分与架构设计呢&#xff…