三天快速学习 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% 的日常使用场景。剩下的,遇到具体需求再去查文档即可!

相关推荐
Mr YiRan5 小时前
C++面向对象继承与操作符重载
开发语言·c++·算法
普通网友8 小时前
Android Jetpack 架构组件最佳实践之“网抑云”APP
android·架构·android jetpack
普通网友8 小时前
原创_Android Jetpack Compose 最全上手指南
android·android jetpack
FDoubleman8 小时前
Android Jetpack之Compose入门(一)
android·android jetpack
普通网友8 小时前
Android Jetpack从入门到精通,干货满满
android·android jetpack
子云心8 小时前
Android Jetpack 系列(七)App Startup 启动优化
android·android jetpack·jetpack·initializer·startup·appstartup
嫩嫩的猿8 小时前
android jetpack compose Model对象更新变量 UI不更新、不刷新问题
android·ui·android jetpack
普通网友8 小时前
Android Jetpack 之 LifeCycle 组件_android 自定义view lifecycle
android·gitee·android jetpack
一只鹿鹿鹿8 小时前
智慧水利一体化建设方案
大数据·运维·开发语言·数据库·物联网