当前位置: 首页 > article >正文

Flutter组合动画学习

如何使用动画控制器和动画来创建一个简单的动画效果。具体来说,它通过一个 `AnimationController` 来控制两个动画,一个用于旋转,一个用于绘制。

前置知识点学习

SingleTickerProviderStateMixin

`SingleTickerProviderStateMixin` 是 Flutter 中一个常用的混入(mixin),用于提供 `Ticker` 对象的简单实现。`Ticker` 是动画时间驱动的核心组件,能够在每一帧时调用回调方法。`SingleTickerProviderStateMixin` 通常用于需要一个 `AnimationController` 的 `State` 类中。

关键点

  • `Ticker`:它是一个计时器,在每一帧调用一个回调。用于驱动动画。
  • `AnimationController`:依赖于 `Ticker` 来更新动画的状态。`AnimationController` 需要一个 `TickerProvider` 来提供 `Ticker`。
  • `SingleTickerProviderStateMixin`:提供一个 `Ticker`,适用于仅需要一个 `Ticker` 的动画场景。

代码示例

以下是一个简单的例子,展示如何在 `State` 类中使用 `SingleTickerProviderStateMixin` 来创建一个动画:

import 'package:flutter/material.dart';

class MyAnimatedWidget2 extends StatefulWidget {
  const MyAnimatedWidget2({super.key});

  @override
  _MyAnimatedPageState createState() {
    return _MyAnimatedPageState();
  }
}

class _MyAnimatedPageState extends State<MyAnimatedWidget2>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    // 初始化 AnimationController
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );

    // 定义一个简单的补间动画(从 0 到 1)
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);

    // 启动动画
    _controller.forward();
  }

  @override
  void dispose() {
    // 释放资源
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Simple Animation"),
      ),
      body: Center(
        child: AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            return Opacity(
              opacity: _animation.value,
              child: Container(
                width: 200,
                height: 200,
                color: Colors.blue,
              ),
            );
          },
        ),
      ),
    );
  }
}

### 解释

  • `with SingleTickerProviderStateMixin`: 这个混入使得 `_MyHomePageState` 类能够作为 `TickerProvider` 使用,提供给 `AnimationController` 使用。
  • `vsync: this`: 这里的 `vsync` 参数指定了 `TickerProvider`,通过 `SingleTickerProviderStateMixin`,`this` 就是当前的 `State`,因此可以直接使用。
  • `AnimationController`: 负责管理动画的状态和时间线。通过 `forward()`、`reverse()` 等方法来控制动画的播放。
  • `Tween` 和 `Animation`: `Tween` 定义了动画的值范围,而 `Animation` 是驱动这个值变化的实际对象。
  • `AnimatedBuilder`: 用于构建依赖于动画的 UI,每次动画状态改变时都会重新构建。

通过 `SingleTickerProviderStateMixin`,你可以轻松地在 Flutter 中实现简单的动画效果,而不必手动管理 `Ticker` 的生命周期。对于需要

总结

`SingleTickerProviderStateMixin` 是一个便捷的工具,用于实现需要单个 `Ticker` 的动画场景。

Opacity

在 Flutter 中,`Opacity` 是一个用于控制子组件透明度的控件。通过调整透明度,你可以使一个组件部分或完全透明。这在构建具有视觉层次和动态效果的用户界面时非常有用。

基本用法

`Opacity` 小部件接受一个 `opacity` 参数,该参数是一个 `double` 类型的值,范围从 0.0 到 1.0:

  • `0.0` 表示完全透明(不可见)。
  • `1.0` 表示完全不透明(可见)。

示例

import 'package:flutter/material.dart';

class OpacityExample extends StatelessWidget {
  const OpacityExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Opacity Example'),
      ),
      body: Center(
        child: Opacity(
          opacity: 0.5,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        ),
      ),
    );
  }
}

关键点

1.性能考虑:`Opacity` 是一个相对简单的控件,但在某些情况下可能会影响性能,特别是当它包裹着一个复杂的子组件时。对于简单的颜色变化,使用 `Colors` 的 `withOpacity` 方法可能更高效。

2.动画效果:与 `AnimationController` 和 `AnimatedBuilder` 配合使用,可以创建平滑的透明度动画。例如,将 `Opacity` 结合 `Tween` 和 `Animation` 来实现淡入淡出效果。

3.子组件属性:`Opacity` 影响其子组件的可见性,但它不会改变子组件的布局特性。即使完全透明,子组件仍然占据布局空间。

4.替代方法:在某些情况下,`FadeTransition` 可能是更好的选择,特别是在需要动画时。`FadeTransition` 专门用于处理透明度动画,并直接与 `Animation` 对象集成。

 使用场景

  • 视觉效果:在创建具有层次的 UI 时,使用透明度来突出显示或淡化特定元素。
  • 动画:在创建淡入淡出效果时,使用 `Opacity` 结合动画控制器。
  • 动态 UI:在响应用户交互时,通过透明度变化来反馈状态变化。

通过灵活运用 `Opacity`,你可以在 Flutter 应用中创建丰富且动态的视觉效果。

RotationTransition

`RotationTransition` 是 Flutter 中的一个动画小部件,用于在一段时间内对其子组件应用旋转动画。它是构建动画的一种便捷方式,特别适合需要对组件进行旋转效果的场景。

主要属性

  • `turns`: 这是一个 `Animation` 类型的属性,定义了旋转的角度。角度是以圈(revolution)为单位的,比如 0.25 表示旋转 90 度(即四分之一圈),1.0 表示旋转 360 度(即一整圈)。
  • `child`: 需要旋转的子组件。`RotationTransition` 将对这个组件施加旋转效果。

 使用方法

`RotationTransition` 通常与 `AnimationController` 和 `Tween` 一起使用。`AnimationController` 用于控制动画的时长和播放状态,而 `Tween` 用于定义动画的起始和结束值。

示例

以下是一个简单的示例,展示如何使用 `RotationTransition` 实现一个简单的旋转动画:

import 'package:flutter/material.dart';

class RotationTransitionExample extends StatefulWidget {
  const RotationTransitionExample({super.key});

  @override
  _RotationTransitionExampleState createState() {
    return _RotationTransitionExampleState();
  }
}

class _RotationTransitionExampleState extends State<RotationTransitionExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('RotationTransition Example'),
      ),
      body: Center(
        child: RotationTransition(
          turns: _controller,
          child: Container(
            width: 100.0,
            height: 100.0,
            color: Colors.blue,
          ),
        ),
      ),
    );
  }
}

解释

  • `AnimationController`: 控制动画的时长和播放方式。在 `initState` 中初始化,并设置为循环播放。
  • `RotationTransition`: 使用 `AnimationController` 的值作为 `turns` 属性。这个值从 0.0 到 1.0 不断变化,实现旋转效果。
  • `child`: 被旋转的组件,在这个例子中是一个蓝色的 `Container`。

 使用场景

  • 旋转图标或按钮:可以用来制作旋转加载指示器、旋转按钮等。
  • 动态效果:在用户交互时,通过旋转来提供视觉反馈。
  • 动画过渡:在组件状态变化时,使用旋转动画增强用户体验。

通过使用 `RotationTransition`,你可以轻松地在 Flutter 应用中实现旋转动画效果,增强应用的动态交互体验。

Tween

在 Flutter 中,`Tween` 是动画框架中一个核心组件,用于定义从一个值到另一个值的插值(interpolation)。它提供了一种简单的方式来指定动画的起始值和结束值,并在动画过程中计算这些值之间的中间值。

主要功能

`Tween` 的主要功能是生成一系列的值,这些值在动画的生命周期内从起始值逐渐变化到结束值。这对于创建平滑的动画效果非常重要。

基本属性

  • `begin`: 动画的起始值。
  • `end`: 动画的结束值。

工作原理

  • `Tween` 通过一个 `Animation` 对象(通常是 `Animation`)来驱动,其 `value` 属性在 0.0 到 1.0 之间变化。
  • `Tween` 的 `lerp(double t)` 方法用于计算动画的当前值,其中 `t` 是 `Animation` 的当前进度。

常见使用场景

1.简单的数值动画: 使用 `Tween` 在两个数值之间插值。

2.颜色动画: 使用 `ColorTween` 在两种颜色之间过渡。

3.尺寸和位置动画: 使用 `SizeTween` 或 `RectTween` 在不同的尺寸或位置之间插值。

示例代码

以下是一个简单的例子,展示如何使用 `Tween` 和 `AnimationController` 创建一个从 0 到 300 的动画:

import 'package:flutter/material.dart';

class TweenExample extends StatefulWidget {
  const TweenExample({super.key});

  @override
  _TweenExampleState createState() {
    return _TweenExampleState();
  }
}

class _TweenExampleState extends State<TweenExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );
    // 定义一个 Tween 从 0 到 300
    _animation = Tween<double>(begin: 0, end: 300).animate(_controller)
      ..addListener(() {
        setState(() {});
      });
    // 启动动画
    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tween Example'),
      ),
      body: Center(
        child: Container(
          width: _animation.value,
          height: _animation.value,
          color: Colors.blue,
        ),
      ),
    );
  }
}

解释

  • `AnimationController`: 控制动画的时长和进度。
  • `Tween(begin: 0, end: 300)`: 定义了一个从 0 到 300 的插值。
  • `animate(_controller)`: 将 `Tween` 连接到 `AnimationController`,以便在动画进度更改时计算当前值。
  • `addListener`: 每当动画的值改变时,重新构建 UI。

Paint

在 Flutter 中,`Paint` 是一个用于配置绘图操作的类。它包含了关于如何绘制图形、文本和图像的详细信息。`Paint` 可以用来指定颜色、样式、阴影、混合模式等属性,是自定义绘制的核心工具之一。

基本属性

`Paint` 有许多属性可以配置绘图行为,以下是一些常用的属性:

  • `color`: 设置绘制内容的颜色。
  • `style`: 定义绘制的风格,可以是 `PaintingStyle.fill`(填充)或 `PaintingStyle.stroke`(描边)。
  • `strokeWidth`: 描边的宽度,仅在 `style` 为 `stroke` 时有效。
  • `blendMode`: 定义颜色如何与现有的绘制内容混合。
  • `shader`: 用于渐变或复杂的着色效果。
  • `maskFilter`: 用于模糊和其他效果。
  • `filterQuality`: 定义图片的质量(如在缩放时)。
  • `isAntiAlias`: 是否对绘制进行抗锯齿处理。
  • `strokeCap`: 描边的末端形状,可以是 `StrokeCap.round`、`StrokeCap.butt`、或 `StrokeCap.square`。
  • `strokeJoin`: 描边的连接方式,可以是 `StrokeJoin.miter`、`StrokeJoin.round`、或 `StrokeJoin.bevel`。

使用场景

`Paint` 通常与 `Canvas` 结合使用,通过 `CustomPainter` 来实现自定义绘制。`CustomPainter` 提供了两个主要方法:`paint(Canvas, Size)` 和 `shouldRepaint(CustomPainter oldDelegate)`。

代码示例

import 'package:flutter/material.dart';
class CirclePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill; // 濉厖鏍峰紡
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width / 4;
    canvas.drawCircle(center, radius, paint);
  }
  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
class PaintExample extends StatelessWidget {
  const PaintExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Paint Example'),
      ),
      body: Center(
        child: CustomPaint(
          size: const Size(200, 200),
          painter: CirclePainter(),
        ),
      ),
    );
  }
}

解释

  • `CustomPainter`: 一个抽象类,用于自定义绘制。通过实现 `paint` 方法来定义绘制逻辑。
  • `Canvas`: 提供了用于绘制的基本操作,比如 `drawCircle`、`drawRect`、`drawPath` 等。
  • `Paint`: 配置绘制操作的细节,比如颜色和样式。
  • `CustomPaint`: 一个小部件,用于在 Flutter UI 中展示自定义绘制的内容。

CustomPaint

`CustomPaint` 是 Flutter 中的一个小部件,用于在屏幕上绘制自定义图形。通过结合 `CustomPainter` 类,`CustomPaint` 可以实现复杂的绘制逻辑。

主要组成部分

1.`CustomPainter`: 一个抽象类,你需要继承并实现它的 `paint` 方法来定义绘制逻辑。`CustomPainter` 是 `CustomPaint` 的核心部分。

2.`CustomPaint` 小部件: 它包含一个 `painter` 属性,该属性接收一个 `CustomPainter`

属性

  • `painter`: 一个 `CustomPainter` 对象,负责绘制主要内容。
  • `foregroundPainter`: 类似于 `painter`,但绘制在子组件的前景(在子组件上面)。
  • `child`: 可选的子组件,当需要在自定义绘制的背景或前景上叠加组件时使用。
  • `size`: 指定 `CustomPaint` 的大小。如果未设置,将会使用子组件的大小。

示例

以下是一个使用 `CustomPaint` 绘制简单图形的示例:

import 'package:flutter/material.dart';

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;
    // 绘制一个圆形
    final circleCenter = Offset(size.width / 2, size.height / 2);
    final circleRadius = size.width / 4;
    canvas.drawCircle(circleCenter, circleRadius, paint);
    // 绘制一个矩形
    final rect = Rect.fromLTWH(50, 50, size.width - 100, size.height - 100);
    paint.color = Colors.red;
    canvas.drawRect(rect, paint);
  }

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

class CustomPaintExample extends StatelessWidget {
  const CustomPaintExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('CustomPaint Example'),
      ),
      body: Center(
        child: CustomPaint(
          size: const Size(200, 200),
          painter: MyPainter(),
        ),
      ),
    );
  }
}

组合动画代码学习

import 'package:flutter/material.dart';

class MyAnimaDemoPage extends StatefulWidget {
  const MyAnimaDemoPage({super.key});

  @override
  _MyAnimaDemoPageState createState() {
    return _MyAnimaDemoPageState();
  }
}

class _MyAnimaDemoPageState extends State<MyAnimaDemoPage>
    with SingleTickerProviderStateMixin {
  late AnimationController controller1;

  late Animation animation2;

  Animation? animation1;

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

    animation1 = Tween(begin: 0.0, end: 200.0).animate(controller1)
      ..addListener(() {
        setState(() {});
      });

    animation2 = Tween(begin: 0.0, end: 1.0).animate(controller1);

    controller1.repeat();
  }

  @override
  void dispose() {
    controller1.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("AnimaDemoPage"),),
      body: RotationTransition(
        turns: animation2 as Animation<double>,
        child: Center(
          child: Container(
            height: 200,
            width: 200,
            color: Colors.blue,
            child: CustomPaint(
              foregroundPainter: _MyAnimationPainter(animation1),
            ),
          ),
        ),
      ),
    );
  }
}


class _MyAnimationPainter extends CustomPainter {

  final Paint _paint = Paint();

  Animation? animation;

  _MyAnimationPainter(this.animation);

  @override
  void paint(Canvas canvas, Size size) {
    _paint
      ..color = Colors.redAccent
      ..strokeWidth = 4
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(const Offset(100, 100), animation!.value * 1.5, _paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

}


http://www.kler.cn/a/450670.html

相关文章:

  • Unity复刻胡闹厨房复盘 模块一 新输入系统订阅链与重绑定
  • 14-zookeeper环境搭建
  • 使用idea创建JDK8的SpringBoot项目
  • 羊城杯2020 easycon
  • 数据结构---------二叉树前序遍历中序遍历后序遍历
  • 数据流图和流程图的区别
  • Linux系统编程深度解析:C语言实战指南
  • 了解RPC
  • 《Web 应用项目开发:从构思到上线的全过程》
  • UE5 渲染管线 学习笔记
  • 全国硕士研究生入学考试(考研)考研时间线之大三
  • 如何获取 ABAP 内表中的重复项
  • springboot容器无法获取@Autowired对象,报null对象空指针问题的解决方式
  • VSCode+WSL作为IDE开发和管理深度学习项目
  • 低代码软件搭建自学第二天——构建拖拽功能
  • SparkSQL与Hive语法差异
  • 畅捷通T+13管理员密码任意重置漏洞
  • 【C++动态规划 前缀和】937. 扣分后的最大得分|2105
  • 5、mysql的读写分离
  • 使用QML实现播放器进度条效果
  • spring mvcservlet跳转页面没有样式效果
  • ubuntu安装nginx
  • leetcode之hot100---24两两交换链表中的节点(C++)
  • Ubuntu离线安装Docker容器
  • vscode添加全局宏定义
  • 青少年编程与数学 02-004 Go语言Web编程 20课题、单元测试