三天快速学习 Flutter(三)之动画

好的!延续前两篇《三天快速学习 Flutter(一)基础与布局》和《(二)事件》"从使用的角度出发,只学最核心、最常用" 的高效风格,第三篇聚焦 动画(Animation)


太多教程繁琐、浪费时间。我们如果只从使用的角度出发,那么 Flutter 动画的学习曲线也可以大大缩短。记住这个公式:

布局解决能看到什么东西,事件决定能做什么事情,动画让布局和事件拥有更好的体验。

搞定这三样,就可以从事基本的开发了。本篇就带你用最短路径掌握 Flutter 动画的核心要点。

一、动画的本质:值的变化

在 Flutter 中,动画的本质不是直接操作 UI,而是驱动一个值(通常是 double 类型)随时间从一个状态平滑地变化到另一个状态。UI 组件监听这个值的变化,并据此重新绘制自己。

例如:

  • 驱动 opacity(透明度)从 1.0 变为 0.0,实现淡出效果。
  • 驱动 width(宽度)从 50.0 变为 200.0,实现伸展效果。
  • 驱动 color(颜色)从红色变为蓝色,实现颜色渐变。
二、最核心的两个概念:AnimationAnimationController

要实现动画,离不开这两个基石:

  1. AnimationController:动画的"总指挥"。

    • 它负责控制 动画的播放(forward())、暂停、反向播放(reverse())和停止。
    • 它内部持有一个从 0.01.0 的值(称为 value),代表动画的进度。
    • 创建时需要传入一个 vsync 参数(通常用 this,即当前 State 对象),用于防止屏幕外的动画消耗不必要的资源。
  2. Animation:动画的"值提供者"。

    • 它本身不控制动画,而是包装 AnimationController 的值,并可以对其应用插值器(Curves)类型转换
    • 最常用的 AnimationTween(补间动画),它可以将 0.0 - 1.0 的范围映射到你想要的任何数值范围(如 50.0 - 200.0)。
三、两种最常用、最简单的动画写法
1. 使用 AnimatedWidget (推荐新手)

这是最简洁的方式,它帮你自动处理了 StatefulWidget 的重建逻辑。

步骤:

  1. State 中创建 AnimationControllerAnimation(如 Tween)。
  2. initState 中初始化它们,并将 Tween 附加到 Controller 上。
  3. 使用 AnimatedContainer, AnimatedOpacity, AnimatedPadding 等预置的 AnimatedWidget,并将你的 Animation 对象赋给其属性。

示例:点击按钮,让一个容器的颜色和大小平滑变化。

复制代码
class MyAnimatedWidget extends StatefulWidget {
  @override
  _MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}

class _MyAnimatedWidgetState extends State<MyAnimatedWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _sizeAnimation;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    // 1. 创建控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    );

    // 2. 创建动画(Tween)
    _sizeAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);
    _colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);
  }

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

  void _toggleAnimation() {
    if (_controller.isCompleted) {
      _controller.reverse(); // 如果动画完成,就倒放
    } else {
      _controller.forward(); // 否则正向播放
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 3. 使用 AnimatedContainer,它会自动监听动画值并重建
        AnimatedContainer(
          width: _sizeAnimation.value,
          height: _sizeAnimation.value,
          color: _colorAnimation.value,
          duration: Duration.zero, // 因为我们用控制器控制,这里设为0
          curve: Curves.easeIn, // 可以在这里或在 animate() 里加曲线
        ),
        ElevatedButton(
          onPressed: _toggleAnimation,
          child: Text('开始/停止 动画'),
        ),
      ],
    );
  }
}
2. 使用 AnimatedBuilder

当你想对任意Widget 添加动画,或者动画逻辑比较复杂时,AnimatedBuilder 是更灵活的选择。

核心思想: AnimatedBuilder 会监听你传给它的 Animation 对象,一旦值发生变化,就只重建它的 builder 函数返回的部分 ,而不是整个父 Widget,性能更好。

示例:让一个文本的字体大小随动画变化。

复制代码
// ... (在 State 中同样需要 _controller 和 _sizeAnimation)

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      // 使用 AnimatedBuilder 包裹需要动画的部件
      AnimatedBuilder(
        animation: _sizeAnimation, // 监听这个动画
        builder: (context, child) {
          return Text(
            'Hello, Flutter!',
            style: TextStyle(fontSize: _sizeAnimation.value),
          );
        },
      ),
      ElevatedButton(
        onPressed: () {
          _controller.forward(from: 0.0); // 从头开始播放
        },
        child: Text('放大文字'),
      ),
    ],
  );
}
四、提升体验的关键:Curves(动画曲线)

默认的动画是线性匀速的,显得很机械。Curves 可以让你的动画拥有"生命感",比如先快后慢 (Curves.easeOut),或有弹性 (Curves.bounceInOut)。

使用方法: 在创建 Animation 时,通过 curve 参数指定。

复制代码
_sizeAnimation = Tween<double>(begin: 50.0, end: 200.0)
    .animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
五、总结:只需记住这几点
  1. 核心目标:动画就是让一个值平滑变化。
  2. 两大基石AnimationController(控制播放) + Animation/Tween(定义值的范围)。
  3. 两种写法
    • 简单场景用 AnimatedContainerAnimatedOpacity 等。
    • 复杂或自定义场景用 AnimatedBuilder
  4. 灵魂点缀 :用 Curves 让动画更自然。
  5. 别忘清理 :在 dispose 方法中调用 _controller.dispose()

搞定这些,你就已经掌握了 Flutter 动画 80% 的日常使用场景。剩下的,遇到具体需求再去查文档即可!

相关推荐
OOJO1 小时前
c++---list介绍
c语言·开发语言·数据结构·c++·算法·list
程序员陆业聪1 小时前
你的 Android App 可能白白损失了 35% 的性能——R8 全模式配置详解
android
笨笨饿3 小时前
29_Z变换在工程中的实际意义
c语言·开发语言·人工智能·单片机·mcu·算法·机器人
Amazing_Cacao3 小时前
深度观察 | 从“产区玄学”到“液态战场”:精品巧克力的终极试金石
学习
艾为电子3 小时前
【技术帖】让接口不再短命:艾为 C-Shielding™ Type-C智能水汽防护技术解析
c语言·开发语言
棉花骑士3 小时前
【AI Agent】面向 Java 工程师的Claude Code Harness 学习指南
java·开发语言
IGAn CTOU4 小时前
PHP使用Redis实战实录2:Redis扩展方法和PHP连接Redis的多种方案
开发语言·redis·php
环黄金线HHJX.4 小时前
TSE框架配置与部署详解
开发语言·python
Vfw3VsDKo4 小时前
Maui 实践:Go 接口以类型之名,给 runtime 传递方法参数
开发语言·后端·golang
深蓝海拓4 小时前
S7-1500PLC学习笔记:MOVE_BLK、MOVE_BLK_VARIANT、BLKMOV的区别
笔记·学习·plc