Flutter 动画系统完全指南引言Flutter 提供了强大而灵活的动画系统允许开发者创建流畅且吸引人的用户界面。本文将深入探讨 Flutter 动画的各种类型和高级技巧。基础概念回顾动画类型补间动画: 在两个值之间平滑过渡物理动画: 模拟真实物理效果Hero动画: 页面间的共享元素过渡核心组件Animation: 动画值AnimationController: 控制动画Tween: 定义值范围Curve: 动画曲线高级技巧一基础动画创建简单动画class FadeAnimation extends StatefulWidget { override _FadeAnimationState createState() _FadeAnimationState(); } class _FadeAnimationState extends StateFadeAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _opacity; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); _opacity Tweendouble(begin: 0.0, end: 1.0).animate(_controller); _controller.forward(); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return FadeTransition( opacity: _opacity, child: const Text(Fading In), ); } }使用 AnimatedBuilderclass ScaleAnimation extends StatefulWidget { override _ScaleAnimationState createState() _ScaleAnimationState(); } class _ScaleAnimationState extends StateScaleAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _scale; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); _scale Tweendouble(begin: 1.0, end: 1.5).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _scale, builder: (context, child) { return Transform.scale( scale: _scale.value, child: child, ); }, child: const FlutterLogo(size: 100), ); } }高级技巧二复杂动画组合并行动画class ParallelAnimation extends StatefulWidget { override _ParallelAnimationState createState() _ParallelAnimationState(); } class _ParallelAnimationState extends StateParallelAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _opacity; late Animationdouble _scale; late AnimationOffset _offset; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 1), vsync: this, ); _opacity Tweendouble(begin: 0.0, end: 1.0).animate(_controller); _scale Tweendouble(begin: 0.5, end: 1.0).animate(_controller); _offset TweenOffset( begin: const Offset(-1.0, 0.0), end: const Offset(0.0, 0.0), ).animate(_controller); } override Widget build(BuildContext context) { return SlideTransition( position: _offset, child: FadeTransition( opacity: _opacity, child: ScaleTransition( scale: _scale, child: const FlutterLogo(size: 100), ), ), ); } }序列动画class SequenceAnimation extends StatefulWidget { override _SequenceAnimationState createState() _SequenceAnimationState(); } class _SequenceAnimationState extends StateSequenceAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 3), vsync: this, ); _animation Tweendouble(begin: 0.0, end: 3.0).animate(_controller); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { double value _animation.value; if (value 1.0) { return Opacity( opacity: value, child: const FlutterLogo(size: 100), ); } else if (value 2.0) { return Transform.scale( scale: 1.0 (value - 1.0), child: const FlutterLogo(size: 100), ); } else { return Transform.rotate( angle: (value - 2.0) * 2 * pi, child: const FlutterLogo(size: 100), ); } }, ); } }高级技巧三物理动画使用 SpringSimulationclass SpringAnimation extends StatefulWidget { override _SpringAnimationState createState() _SpringAnimationState(); } class _SpringAnimationState extends StateSpringAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController(vsync: this); _animation _controller.drive( Tweendouble(begin: -100.0, end: 0.0), ); _controller.animateWith( SpringSimulation( SpringDescription( mass: 1.0, stiffness: 100.0, damping: 10.0, ), 0.0, 1.0, 0.0, ), ); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, _animation.value), child: const FlutterLogo(size: 100), ); }, ); } }弹跳动画class BounceAnimation extends StatefulWidget { override _BounceAnimationState createState() _BounceAnimationState(); } class _BounceAnimationState extends StateBounceAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); _animation Tweendouble(begin: 0.0, end: 100.0).animate( CurvedAnimation( parent: _controller, curve: Curves.bounceOut, ), ); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, -_animation.value), child: const FlutterLogo(size: 50), ); }, ); } }高级技巧四自定义动画自定义 Curveclass CustomCurve extends Curve { override double transformInternal(double t) { return sin(t * pi) * exp(-t * 2); } } class CustomCurveAnimation extends StatefulWidget { override _CustomCurveAnimationState createState() _CustomCurveAnimationState(); } class _CustomCurveAnimationState extends StateCustomCurveAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 3), vsync: this, )..repeat(); _animation Tweendouble(begin: 0.0, end: 200.0).animate( CurvedAnimation(parent: _controller, curve: CustomCurve()), ); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(_animation.value, 0), child: const FlutterLogo(size: 50), ); }, ); } }自定义 Tweenclass ColorTween extends TweenColor { ColorTween({required Color begin, required Color end}) : super(begin: begin, end: end); override Color lerp(double t) { final r (begin!.red (end!.red - begin!.red) * t).round(); final g (begin!.green (end!.green - begin!.green) * t).round(); final b (begin!.blue (end!.blue - begin!.blue) * t).round(); return Color.fromARGB(255, r, g, b); } } class ColorAnimation extends StatefulWidget { override _ColorAnimationState createState() _ColorAnimationState(); } class _ColorAnimationState extends StateColorAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late AnimationColor _colorAnimation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); _colorAnimation ColorTween( begin: Colors.blue, end: Colors.red, ).animate(_controller); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _colorAnimation, builder: (context, child) { return Container( width: 200, height: 200, color: _colorAnimation.value, ); }, ); } }实战案例页面过渡动画class SlidePageRoute extends PageRouteBuilder { final Widget page; SlidePageRoute({required this.page}) : super( pageBuilder: ( BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation, ) page, transitionsBuilder: ( BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation, Widget child, ) SlideTransition( position: TweenOffset( begin: const Offset(1.0, 0.0), end: Offset.zero, ).animate(animation), child: child, ), ); } // 使用 Navigator.push(context, SlidePageRoute(page: const NextPage()));实战案例列表项动画class AnimatedListExample extends StatefulWidget { override _AnimatedListExampleState createState() _AnimatedListExampleState(); } class _AnimatedListExampleState extends StateAnimatedListExample { final GlobalKeyAnimatedListState _listKey GlobalKey(); ListString _items [Item 1, Item 2, Item 3]; void _addItem() { setState(() { final index _items.length; _items.add(Item ${index 1}); _listKey.currentState!.insertItem(index); }); } void _removeItem(int index) { setState(() { _listKey.currentState!.removeItem( index, (context, animation) SizeTransition( sizeFactor: animation, child: const Card(), ), ); _items.removeAt(index); }); } override Widget build(BuildContext context) { return Column( children: [ ElevatedButton(onPressed: _addItem, child: const Text(Add)), Expanded( child: AnimatedList( key: _listKey, initialItemCount: _items.length, itemBuilder: (context, index, animation) { return SlideTransition( position: animation.drive( TweenOffset( begin: const Offset(-1.0, 0.0), end: Offset.zero, ), ), child: ListTile( title: Text(_items[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () _removeItem(index), ), ), ); }, ), ), ], ); } }实战案例进度指示器动画class CustomProgressIndicator extends StatefulWidget { final double progress; const CustomProgressIndicator({super.key, required this.progress}); override _CustomProgressIndicatorState createState() _CustomProgressIndicatorState(); } class _CustomProgressIndicatorState extends StateCustomProgressIndicator with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); _animation Tweendouble(begin: 0.0, end: widget.progress).animate(_controller); _controller.forward(); } override void didUpdateWidget(CustomProgressIndicator oldWidget) { super.didUpdateWidget(oldWidget); _animation Tweendouble(begin: _animation.value, end: widget.progress) .animate(_controller); _controller.reset(); _controller.forward(); } override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Container( height: 8, decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: Colors.grey[200], ), child: FractionallySizedBox( widthFactor: _animation.value, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), gradient: const LinearGradient( colors: [Colors.blue, Colors.purple], ), ), ), ), ); }, ); } }常见问题与解决方案Q1动画卡顿A检查是否使用了SingleTickerProviderStateMixinclass MyWidget extends StatefulWidget { override _MyWidgetState createState() _MyWidgetState(); } class _MyWidgetState extends StateMyWidget with SingleTickerProviderStateMixin { // 确保使用这个 late AnimationController _controller; }Q2动画不播放A确保调用了forward()_controller.forward(); // 启动动画Q3动画内存泄漏A在dispose()中释放控制器override void dispose() { _controller.dispose(); // 必须释放 super.dispose(); }最佳实践1. 使用 AnimatedWidgetclass FadeWidget extends AnimatedWidget { const FadeWidget({ super.key, required Animationdouble animation, required this.child, }) : super(listenable: animation); final Widget child; override Widget build(BuildContext context) { final animation listenable as Animationdouble; return Opacity(opacity: animation.value, child: child); } }2. 复用 AnimationController// 推荐 class MyWidget extends StatefulWidget { override _MyWidgetState createState() _MyWidgetState(); } class _MyWidgetState extends StateMyWidget with SingleTickerProviderStateMixin { late AnimationController _controller; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 1), vsync: this, ); } void animate() { _controller.reset(); _controller.forward(); } }3. 使用 CurvedAnimationCurvedAnimation( parent: _controller, curve: Curves.easeInOut, )总结Flutter 的动画系统非常强大。通过本文的学习你应该能够创建基础补间动画组合多个动画使用物理模拟动画创建自定义动画实现页面过渡动画掌握这些技巧能够帮助你创建更加流畅和吸引人的用户界面。