五、Flutter动画

发布于:2025-07-07 ⋅ 阅读:(23) ⋅ 点赞:(0)

1. Flutter 中动画的基本概念是什么?

在 Flutter 中,动画是通过在一段时间内连续改变属性值来实现的视觉效果变化。核心概念包括:

概念 说明
动画值 随时间变化的数值(通常是 0.0 → 1.0)
动画控制器 管理动画的播放、停止、反转等操作
补间 (Tween) 定义起始值和结束值之间的过渡(如位置、大小、颜色等)
动画曲线 控制动画变化速率(如加速、减速、弹跳等)
动画监听器 在动画值变化时更新 UI
动画状态 运行中 (forward)、完成 (completed)、反转中 (reverse)、停止 (dismissed)

动画分类

  • 隐式动画:自动处理的简单动画(如 AnimatedContainer
  • 显式动画:需要手动控制的复杂动画(使用 AnimationController

2. 解释 AnimationController 和 Tween 的作用

AnimationController

  • 作用:管理动画的播放状态和持续时间
  • 特点
    • 需要 TickerProvide*(如 SingleTickerProviderStateMixin
    • 默认输出 0.0 → 1.0 的值
    • 控制动画播放 (forward())、停止 (stop())、反转 (reverse())
  • 创建
late AnimationController _controller;


void initState() {
  super.initState();
  _controller = AnimationController(
    duration: const Duration(seconds: 2),  // 动画时长
    vsync: this,  // 使用 TickerProvider
  );
}

Tween

  • 作用:定义动画的值范围(如颜色、大小、位置等)
  • 特点
    • 将 0.0→1.0 映射到实际值范围
    • 支持多种数据类型(ColorTwee*, SizeTween 等)
  • 使用
final Animation<double> _sizeAnim = Tween<double>(
  begin: 50.0, 
  end: 200.0,
).animate(_controller);

3. 如何实现一个补间(Tween)动画?

步骤

  1. 创建 AnimationController
  2. 定义 Tween 并绑定控制器
  3. 添加监听器重建 UI
  4. 启动动画

示例代码

class TweenAnimationDemo extends StatefulWidget {
  
  _TweenAnimationDemoState createState() => _TweenAnimationDemoState();
}

class _TweenAnimationDemoState extends State<TweenAnimationDemo> 
  with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _sizeAnim;
  late Animation<Color?> _colorAnim;

  
  void initState() {
    super.initState();
    // 1. 创建控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true); // 循环播放

    // 2. 创建补间动画
    _sizeAnim = Tween<double>(begin: 50, end: 200).animate(_controller);
    _colorAnim = ColorTween(begin: Colors.blue, end: Colors.red).animate(_controller);
  }

  
  Widget build(BuildContext context) {
    // 3. 使用 AnimatedBuilder 优化性能
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Center(
          child: Container(
            width: _sizeAnim.value,
            height: _sizeAnim.value,
            color: _colorAnim.value,
          ),
        );
      },
    );
  }

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

4. 什么是隐式动画?举例说明

隐式动画:只需设置目标值,Flutter 自动处理动画过程的简化动画。

特点

  • 无需管理 AnimationController
  • 内置 300ms 默认动画时长
  • 通过 setState() 改变属性值自动触发

常用隐式动画组件

组件 作用
AnimatedContainer 容器属性变化(大小/颜色等)
AnimatedOpacity 透明度变化
AnimatedPositioned 位置变化(Stack 内)
AnimatedAlign 对齐方式变化

示例:点击改变容器大小和颜色

class ImplicitAnimationDemo extends StatefulWidget {
  
  _ImplicitAnimationDemoState createState() => _ImplicitAnimationDemoState();
}

class _ImplicitAnimationDemoState extends State<ImplicitAnimationDemo> {
  double _size = 100;
  Color _color = Colors.blue;

  void _animate() {
    setState(() {
      _size = _size == 100 ? 200 : 100;
      _color = _color == Colors.blue ? Colors.green : Colors.blue;
    });
  }

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _animate,
      child: AnimatedContainer(
        duration: Duration(seconds: 1), // 动画时长
        width: _size,
        height: _size,
        color: _color,
        curve: Curves.easeInOut, // 动画曲线
        child: Center(child: Text('点击我')),
      ),
    );
  }
}

5. 如何实现自定义复杂动画?

对于复杂动画(如路径动画、物理动画、多动画同步),推荐使用:

1. 组合多个动画

late Animation<double> _sizeAnim;
late Animation<double> _rotationAnim;


void initState() {
  super.initState();
  _sizeAnim = Tween(begin: 0.0, end: 1.0).animate(
    CurvedAnimation(
      parent: _controller,
      curve: Interval(0.0, 0.5), // 只在前半段执行
    ),
  );

  _rotationAnim = Tween(begin: 0.0, end: 2 * pi).animate(
    CurvedAnimation(
      parent: _controller,
      curve: Interval(0.5, 1.0), // 只在后半段执行
    ),
  );
}

2. 使用物理动画(SpringSimulation)

void _runSpringAnimation() {
  final spring = SpringSimulation(
    SpringDescription(mass: 1, stiffness: 100, damping: 10),
    0.0,   // 起始位置
    300.0, // 目标位置
    10.0,  // 初始速度
  );

  _controller.animateWith(spring);
}

3. 自定义动画曲线

final customCurve = CurveTween(
  curve: Curves.easeInOutBack,
);

_animation = customCurve.animate(_controller);

4. 使用动画状态机

_controller.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    _controller.reverse();
  } else if (status == AnimationStatus.dismissed) {
    _controller.forward();
  }
});

完整示例:弹跳球效果

class BouncingBallDemo extends StatefulWidget {
  
  _BouncingBallDemoState createState() => _BouncingBallDemoState();
}

class _BouncingBallDemoState extends State<BouncingBallDemo>
  with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _bounceAnim;

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

    // 使用弹性曲线模拟弹跳
    _bounceAnim = Tween<double>(begin: 0, end: 300).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.elasticOut, // 弹性效果
      ),
    );
  }

  
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Stack(
          children: [
            Positioned(
              bottom: _bounceAnim.value,
              left: MediaQuery.of(context).size.width / 2 - 25,
              child: Container(
                width: 50,
                height: 50,
                decoration: BoxDecoration(
                  color: Colors.red,
                  shape: BoxShape.circle,
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}