一、动画基础:从零开始理解Flutter动画

在Flutter中,动画的核心是AnimationAnimationController。我们先从一个最简单的透明度动画开始:

import 'package:flutter/material.dart';

class FadeInDemo extends StatefulWidget {
  @override
  _FadeInDemoState createState() => _FadeInDemoState();
}

class _FadeInDemoState extends State<FadeInDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;  // 控制动画的启动、停止和进度
  late Animation<double> _animation;     // 定义动画的值范围

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),  // 动画持续2秒
      vsync: this,                           // 绑定到当前Widget
    );
    _animation = Tween(begin: 0.0, end: 1.0).animate(_controller);  // 透明度从0到1
    _controller.forward();  // 启动动画
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation,
      child: Container(
        width: 200,
        height: 200,
        color: Colors.blue,
      ),
    );
  }

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

注释说明

  • Tween定义了动画的起始值和结束值。
  • vsync参数用于防止动画在后台运行时消耗资源。

二、进阶技巧:组合动画与物理效果

Flutter的CurvedAnimation可以让动画更自然。比如实现一个弹跳效果:

class BounceDemo extends StatefulWidget {
  @override
  _BounceDemoState createState() => _BounceDemoState();
}

class _BounceDemoState extends State<BounceDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );
    _animation = CurvedAnimation(
      parent: _controller,
      curve: Curves.bounceOut,  // 使用预置的弹跳曲线
    )..addListener(() => setState(() {}));  // 强制重绘
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Transform.scale(
      scale: _animation.value,  // 缩放比例随动画值变化
      child: Container(
        width: 100,
        height: 100,
        color: Colors.red,
      ),
    );
  }
}

关联技术Curves类提供了多种预设动画曲线,如easeInelasticOut等。

三、交互式动画:手势与动画结合

通过手势控制动画进度,比如拖动滑块改变动画位置:

class DragAnimationDemo extends StatefulWidget {
  @override
  _DragAnimationDemoState createState() => _DragAnimationDemoState();
}

class _DragAnimationDemoState extends State<DragAnimationDemo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _animation;
  double _dragProgress = 0.0;  // 记录拖动进度

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    );
    _animation = Tween<Offset>(
      begin: Offset.zero,
      end: const Offset(1.5, 0.0),  // 水平移动1.5倍宽度
    ).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onHorizontalDragUpdate: (details) {
        setState(() {
          _dragProgress = (_dragProgress + details.primaryDelta! / 300).clamp(0.0, 1.0);
          _controller.value = _dragProgress;  // 同步动画进度
        });
      },
      child: SlideTransition(
        position: _animation,
        child: Container(
          width: 100,
          height: 100,
          color: Colors.green,
        ),
      ),
    );
  }
}

注意事项

  • 手势数据需要归一化到[0,1]范围。
  • 实际项目中建议使用GestureDetectoronPanUpdate更精确。

四、复杂场景:Hero动画与路由切换

Hero动画用于页面间共享元素的过渡效果:

// 页面1
class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => Page2())),
      child: Hero(
        tag: 'sharedElement',  // 唯一标识
        child: Container(
          width: 100,
          height: 100,
          color: Colors.purple,
        ),
      ),
    );
  }
}

// 页面2
class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Hero(
      tag: 'sharedElement',
      child: Container(
        width: 200,
        height: 200,  // 尺寸变化会自动过渡
        color: Colors.purple,
      ),
    );
  }
}

技术优缺点

  • 优点:无需手动管理动画,代码简洁。
  • 缺点:仅适用于全屏路由切换场景。

应用场景与技术总结

典型场景

  1. 加载状态提示(旋转/淡入)
  2. 用户引导(高亮聚焦)
  3. 游戏交互(物理引擎)

注意事项

  • 避免过度使用动画导致性能问题。
  • 使用AnimatedBuilder优化性能,避免不必要的重绘。

总结:Flutter动画体系灵活强大,从基础到复杂交互均可覆盖。掌握核心类(AnimationTweenCurves)和设计模式(如AnimatedWidget),能显著提升用户体验。