Flutter 动画控制器:打造流畅的动画体验
Flutter 动画控制器打造流畅的动画体验掌握 Flutter 动画控制器的高级技巧创造流畅而优雅的动画效果。一、动画控制器概述作为一名把代码当散文写的 UI 匠人我对 Flutter 动画控制器有着独特的见解。动画控制器是 Flutter 动画系统的核心它可以让我们精确控制动画的播放、暂停、倒放等。从简单的动画到复杂的动画序列动画控制器为我们提供了一套强大的动画创作工具。就像电影导演手里的摄像机一样动画控制器让我们可以精确掌控动画的每一个细节。二、基础动画控制器1. 创建动画控制器import package:flutter/material.dart; class BasicAnimationController extends StatefulWidget { const BasicAnimationController({super.key}); override StateBasicAnimationController createState() _BasicAnimationControllerState(); } class _BasicAnimationControllerState extends StateBasicAnimationController with SingleTickerProviderStateMixin { late AnimationController _controller; override void initState() { super.initState(); // 创建动画控制器 _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); } override void dispose() { // 释放资源 _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(基础动画控制器)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.rotate( angle: _controller.value * 2 * 3.14159, child: Container( width: 100, height: 100, color: Colors.blue, ), ); }, ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () _controller.forward(), child: const Text(播放), ), const SizedBox(width: 10), ElevatedButton( onPressed: () _controller.reverse(), child: const Text(倒放), ), const SizedBox(width: 10), ElevatedButton( onPressed: () _controller.reset(), child: const Text(重置), ), ], ), ], ), ), ); } }2. 动画值监听class AnimationValueListener extends StatefulWidget { const AnimationValueListener({super.key}); override StateAnimationValueListener createState() _AnimationValueListenerState(); } class _AnimationValueListenerState extends StateAnimationValueListener with SingleTickerProviderStateMixin { late AnimationController _controller; double _animationValue 0.0; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); // 监听动画值变化 _controller.addListener(() { setState(() { _animationValue _controller.value; }); }); // 监听动画状态变化 _controller.addStatusListener((status) { print(Animation Status: $status); }); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(动画值监听)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(动画值: ${_animationValue.toStringAsFixed(2)}), const SizedBox(height: 20), Container( width: 200, height: 10, color: Colors.grey[300], child: FractionallySizedBox( widthFactor: _animationValue, child: Container(color: Colors.blue), ), ), const SizedBox(height: 20), ElevatedButton( onPressed: () _controller.forward(), child: const Text(播放动画), ), ], ), ), ); } }3. 动画状态class AnimationStatusExample extends StatefulWidget { const AnimationStatusExample({super.key}); override StateAnimationStatusExample createState() _AnimationStatusExampleState(); } class _AnimationStatusExampleState extends StateAnimationStatusExample with SingleTickerProviderStateMixin { late AnimationController _controller; AnimationStatus _status AnimationStatus.dismissed; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); _controller.addStatusListener((status) { setState(() { _status status; }); }); } override void dispose() { _controller.dispose(); super.dispose(); } String getStatusText() { switch (_status) { case AnimationStatus.dismissed: return 已停止; case AnimationStatus.forward: return 正向播放中; case AnimationStatus.reverse: return 反向播放中; case AnimationStatus.completed: return 已完成; } } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(动画状态)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(状态: ${getStatusText()}), const SizedBox(height: 20), AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.scale( scale: 0.5 _controller.value * 0.5, child: Container( width: 100, height: 100, color: Colors.blue, ), ); }, ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () _controller.forward(), child: const Text(正向), ), const SizedBox(width: 10), ElevatedButton( onPressed: () _controller.reverse(), child: const Text(反向), ), const SizedBox(width: 10), ElevatedButton( onPressed: () _controller.stop(), child: const Text(停止), ), ], ), ], ), ), ); } }三、高级动画控制器1. 动画重复class RepeatingAnimation extends StatefulWidget { const RepeatingAnimation({super.key}); override StateRepeatingAnimation createState() _RepeatingAnimationState(); } class _RepeatingAnimationState extends StateRepeatingAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 1), vsync: this, ); // 无限重复 _controller.repeat(); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(重复动画)), body: Center( child: AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.rotate( angle: _controller.value * 2 * 3.14159, child: Container( width: 100, height: 100, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(_controller.value * 50), ), ), ); }, ), ), ); } } // 往返动画 class RepeatingAnimationReverse extends StatefulWidget { const RepeatingAnimationReverse({super.key}); override StateRepeatingAnimationReverse createState() _RepeatingAnimationReverseState(); } class _RepeatingAnimationReverseState extends StateRepeatingAnimationReverse with SingleTickerProviderStateMixin { late AnimationController _controller; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 1), vsync: this, ); // 往返动画 _controller.repeat(reverse: true); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(往返动画)), body: Center( child: AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.scale( scale: 0.5 _controller.value, child: Container( width: 100, height: 100, color: Colors.blue, ), ); }, ), ), ); } }2. 动画曲线class CurvedAnimationExample extends StatefulWidget { const CurvedAnimationExample({super.key}); override StateCurvedAnimationExample createState() _CurvedAnimationExampleState(); } class _CurvedAnimationExampleState extends StateCurvedAnimationExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); // 使用曲线 _animation CurvedAnimation( parent: _controller, curve: Curves.easeInOut, ); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(动画曲线)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, -100 * _animation.value), child: Container( width: 100, height: 100, color: Colors.blue, ), ); }, ), const SizedBox(height: 20), ElevatedButton( onPressed: () { if (_controller.status AnimationStatus.completed) { _controller.reverse(); } else { _controller.forward(); } }, child: const Text(切换), ), ], ), ), ); } } // 自定义曲线 class CustomCurveExample extends StatefulWidget { const CustomCurveExample({super.key}); override StateCustomCurveExample createState() _CustomCurveExampleState(); } class _CustomCurveExampleState extends StateCustomCurveExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); // 自定义曲线 _animation CurvedAnimation( parent: _controller, curve: _BounceCurve(), ); _controller.forward(); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(自定义曲线)), body: Center( child: AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, -150 * _animation.value), child: Container( width: 50, height: 50, decoration: const BoxDecoration( color: Colors.blue, shape: BoxShape.circle, ), ), ); }, ), ), ); } } class _BounceCurve extends Curve { override double transform(double t) { if (t 0.5) { return 4 * t * t; } else { return 1 - 4 * (1 - t) * (1 - t); } } }3. Tween 动画class TweenAnimationExample extends StatefulWidget { const TweenAnimationExample({super.key}); override StateTweenAnimationExample createState() _TweenAnimationExampleState(); } class _TweenAnimationExampleState extends StateTweenAnimationExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _sizeAnimation; late AnimationColor? _colorAnimation; late AnimationOffset _offsetAnimation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); // 尺寸 Tween _sizeAnimation Tweendouble(begin: 50, end: 200).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); // 颜色 Tween _colorAnimation ColorTween(begin: Colors.blue, end: Colors.red).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); // 位置 Tween _offsetAnimation TweenOffset( begin: const Offset(-1, 0), end: const Offset(1, 0), ).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); _controller.repeat(reverse: true); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(Tween 动画)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 尺寸动画 AnimatedBuilder( animation: _sizeAnimation, builder: (context, child) { return Container( width: _sizeAnimation.value, height: _sizeAnimation.value, color: _colorAnimation.value, ); }, ), const SizedBox(height: 20), // 位置动画 SlideTransition( position: _offsetAnimation, child: Container( width: 50, height: 50, color: Colors.green, ), ), ], ), ), ); } }四、实战案例1. 加载动画class LoadingAnimation extends StatefulWidget { const LoadingAnimation({super.key}); override StateLoadingAnimation createState() _LoadingAnimationState(); } class _LoadingAnimationState extends StateLoadingAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _rotationAnimation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 2), vsync: this, ); _rotationAnimation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.linear), ); _controller.repeat(); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(加载动画)), body: Center( child: AnimatedBuilder( animation: _rotationAnimation, builder: (context, child) { return Transform.rotate( angle: _rotationAnimation.value * 2 * 3.14159, child: Stack( alignment: Alignment.center, children: [ Container( width: 100, height: 100, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Colors.blue, width: 4, ), ), ), Positioned( top: 0, child: Container( width: 20, height: 20, decoration: const BoxDecoration( color: Colors.blue, shape: BoxShape.circle, ), ), ), ], ), ); }, ), ), ); } }2. 卡片翻转动画class CardFlipAnimation extends StatefulWidget { const CardFlipAnimation({super.key}); override StateCardFlipAnimation createState() _CardFlipAnimationState(); } class _CardFlipAnimationState extends StateCardFlipAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; bool _isFront true; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 600), vsync: this, ); _animation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } override void dispose() { _controller.dispose(); super.dispose(); } void _flipCard() { if (_isFront) { _controller.forward(); } else { _controller.reverse(); } _isFront !_isFront; } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(卡片翻转动画)), body: Center( child: GestureDetector( onTap: _flipCard, child: AnimatedBuilder( animation: _animation, builder: (context, child) { final angle _animation.value * 3.14159; final transform Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateY(angle); return Transform( transform: transform, alignment: Alignment.center, child: Container( width: 200, height: 300, decoration: BoxDecoration( color: _animation.value 0.5 ? Colors.blue : Colors.red, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Center( child: Text( _animation.value 0.5 ? 正面 : 背面, style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), ), ), ); }, ), ), ), ); } }3. 下拉刷新动画class PullToRefreshAnimation extends StatefulWidget { const PullToRefreshAnimation({super.key}); override StatePullToRefreshAnimation createState() _PullToRefreshAnimationState(); } class _PullToRefreshAnimationState extends StatePullToRefreshAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _scaleAnimation; late Animationdouble _rotationAnimation; bool _isRefreshing false; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(seconds: 1), vsync: this, ); _scaleAnimation Tweendouble(begin: 0.5, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _rotationAnimation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.linear), ); } override void dispose() { _controller.dispose(); super.dispose(); } Futurevoid _refresh() async { setState(() { _isRefreshing true; }); _controller.repeat(); // 模拟网络请求 await Future.delayed(const Duration(seconds: 2)); _controller.stop(); setState(() { _isRefreshing false; }); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(下拉刷新动画)), body: RefreshIndicator( onRefresh: _refresh, child: ListView.builder( itemCount: 20, itemBuilder: (context, index) { return ListTile( title: Text(Item $index), leading: _isRefreshing ? AnimatedBuilder( animation: _rotationAnimation, builder: (context, child) { return Transform.rotate( angle: _rotationAnimation.value * 2 * 3.14159, child: const Icon(Icons.refresh), ); }, ) : const Icon(Icons.list), ); }, ), ), ); } }4. 按钮波纹动画class RippleButtonAnimation extends StatefulWidget { const RippleButtonAnimation({super.key}); override StateRippleButtonAnimation createState() _RippleButtonAnimationState(); } class _RippleButtonAnimationState extends StateRippleButtonAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _scaleAnimation; late Animationdouble _fadeAnimation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); _scaleAnimation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _fadeAnimation Tweendouble(begin: 1, end: 0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); } override void dispose() { _controller.dispose(); super.dispose(); } void _onTap() { _controller.forward(from: 0); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(按钮波纹动画)), body: Center( child: GestureDetector( onTap: _onTap, child: Container( width: 200, height: 60, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(30), ), child: Stack( alignment: Alignment.center, children: [ AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: Opacity( opacity: _fadeAnimation.value, child: Container( width: 200, height: 60, decoration: BoxDecoration( color: Colors.white.withOpacity(0.3), borderRadius: BorderRadius.circular(30), ), ), ), ); }, ), const Text( 点击我, style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), ), ), ), ); } }5. 页面转场动画class PageTransitionAnimation extends StatefulWidget { const PageTransitionAnimation({super.key}); override StatePageTransitionAnimation createState() _PageTransitionAnimationState(); } class _PageTransitionAnimationState extends StatePageTransitionAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _scaleAnimation; late AnimationOffset _slideAnimation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); _scaleAnimation Tweendouble(begin: 0.8, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _slideAnimation TweenOffset( begin: const Offset(0, 0.1), end: const Offset(0, 0), ).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _controller.forward(); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(页面转场动画)), body: AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: SlideTransition( position: _slideAnimation, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(16), ), child: const Center( child: Text( 新页面, style: TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { _controller.reverse(); Future.delayed(const Duration(milliseconds: 500), () { Navigator.pop(context); }); }, child: const Text(返回), ), ], ), ), ), ); }, ), ); } }五、性能优化及时释放资源在 dispose 中释放动画控制器使用 AnimatedBuilder避免不必要的重建合理设置动画时长一般在 200-500ms 之间避免复杂动画在低性能设备上简化动画使用硬件加速结合 Transform 使用// 性能优化 class OptimizedAnimation extends StatefulWidget { const OptimizedAnimation({super.key}); override StateOptimizedAnimation createState() _OptimizedAnimationState(); } class _OptimizedAnimationState extends StateOptimizedAnimation with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); _animation CurvedAnimation( parent: _controller, curve: Curves.easeInOut, ); } override void dispose() { _controller.dispose(); super.dispose(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(性能优化)), body: Center( // 使用 AnimatedBuilder 优化性能 child: AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, -100 * _animation.value), child: child, // 重用 child ); }, // 静态部分作为 child 传入 child: Container( width: 100, height: 100, color: Colors.blue, ), ), ), ); } }六、最佳实践使用 SingleTickerProviderStateMixin单个动画控制器时使用使用 TickerProviderStateMixin多个动画控制器时使用合理组织动画代码将动画逻辑封装在单独的类中提供动画控制接口允许外部控制动画测试动画性能在不同设备上测试动画保持动画流畅确保动画在 60fps七、总结Flutter 动画控制器是创造流畅动画效果的核心工具。通过掌握动画控制器的高级技巧我们可以精确控制动画的播放、暂停、倒放等创造出流畅而优雅的动画效果。作为一名 UI 匠人我建议在项目中合理使用动画控制器让应用的交互更加生动有趣。动画控制器是动画的指挥棒它让我们可以精确掌控动画的每一个细节。#flutter #animation #animation-controller #frontend #ui
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2501049.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!