Flutter 动画基础:让界面活起来

张开发
2026/4/7 8:16:35 15 分钟阅读

分享文章

Flutter 动画基础:让界面活起来
Flutter 动画基础让界面活起来从基础动画开始掌握 Flutter 动画系统的核心概念。一、动画的重要性作为一名追求像素级还原的 UI 匠人我深知动画在用户体验中的重要性。好的动画能够引导用户注意力、提供反馈、增强交互体验让界面变得生动有趣。Flutter 提供了强大的动画系统让我们能够轻松创建各种动画效果。二、基础动画类型1. 隐式动画import package:flutter/material.dart; class ImplicitAnimationExample extends StatefulWidget { override _ImplicitAnimationExampleState createState() _ImplicitAnimationExampleState(); } class _ImplicitAnimationExampleState extends StateImplicitAnimationExample { bool _isExpanded false; override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(隐式动画)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedContainer( width: _isExpanded ? 200 : 100, height: _isExpanded ? 200 : 100, color: _isExpanded ? Colors.blue : Colors.red, duration: Duration(seconds: 1), curve: Curves.easeInOut, ), SizedBox(height: 24), ElevatedButton( onPressed: () { setState(() { _isExpanded !_isExpanded; }); }, child: Text(_isExpanded ? 收起 : 展开), ), ], ), ), ); } }2. 显式动画class ExplicitAnimationExample extends StatefulWidget { override _ExplicitAnimationExampleState createState() _ExplicitAnimationExampleState(); } class _ExplicitAnimationExampleState extends StateExplicitAnimationExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: Duration(seconds: 2), vsync: this, ); _animation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.bounceOut), ); _controller.forward(); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(显式动画)), body: Center( child: AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.scale( scale: _animation.value, child: Container( width: 100, height: 100, color: Colors.green, ), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { if (_controller.isCompleted) { _controller.reverse(); } else { _controller.forward(); } }, child: Icon(Icons.refresh), ), ); } override void dispose() { _controller.dispose(); super.dispose(); } }三、常用动画组件1. AnimatedOpacityclass AnimatedOpacityExample extends StatefulWidget { override _AnimatedOpacityExampleState createState() _AnimatedOpacityExampleState(); } class _AnimatedOpacityExampleState extends StateAnimatedOpacityExample { double _opacity 1.0; override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(AnimatedOpacity)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedOpacity( opacity: _opacity, duration: Duration(seconds: 1), child: Container( width: 200, height: 200, color: Colors.purple, ), ), SizedBox(height: 24), ElevatedButton( onPressed: () { setState(() { _opacity _opacity 1.0 ? 0.3 : 1.0; }); }, child: Text(_opacity 1.0 ? 淡出 : 淡入), ), ], ), ), ); } }2. AnimatedPositionedclass AnimatedPositionedExample extends StatefulWidget { override _AnimatedPositionedExampleState createState() _AnimatedPositionedExampleState(); } class _AnimatedPositionedExampleState extends StateAnimatedPositionedExample { bool _isMoved false; override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(AnimatedPositioned)), body: Stack( children: [ Container( width: double.infinity, height: double.infinity, color: Colors.grey[200], ), AnimatedPositioned( left: _isMoved ? 100 : 50, top: _isMoved ? 200 : 100, duration: Duration(seconds: 1), curve: Curves.easeInOut, child: Container( width: 100, height: 100, color: Colors.orange, ), ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { _isMoved !_isMoved; }); }, child: Icon(Icons.move_down), ), ); } }3. AnimatedContainerclass AnimatedContainerExample extends StatefulWidget { override _AnimatedContainerExampleState createState() _AnimatedContainerExampleState(); } class _AnimatedContainerExampleState extends StateAnimatedContainerExample { bool _isChanged false; override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(AnimatedContainer)), body: Center( child: AnimatedContainer( width: _isChanged ? 250 : 200, height: _isChanged ? 250 : 200, decoration: BoxDecoration( color: _isChanged ? Colors.blue : Colors.red, borderRadius: _isChanged ? BorderRadius.circular(50) : BorderRadius.circular(10), boxShadow: _isChanged ? [ BoxShadow( color: Colors.black.withOpacity(0.3), spreadRadius: 5, blurRadius: 10, offset: Offset(0, 5), ), ] : [], ), duration: Duration(seconds: 1), curve: Curves.easeInOut, child: Center( child: Text( 点击改变, style: TextStyle(color: Colors.white, fontSize: 16), ), ), ), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { _isChanged !_isChanged; }); }, child: Icon(Icons.change_history), ), ); } }四、动画曲线class AnimationCurvesExample extends StatefulWidget { override _AnimationCurvesExampleState createState() _AnimationCurvesExampleState(); } class _AnimationCurvesExampleState extends StateAnimationCurvesExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _animation; override void initState() { super.initState(); _controller AnimationController( duration: Duration(seconds: 2), vsync: this, )..repeat(reverse: true); _animation Tweendouble(begin: 0, end: 1).animate( CurvedAnimation(parent: _controller, curve: Curves.bounceOut), ); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(动画曲线)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.translate( offset: Offset(0, _animation.value * 200 - 100), child: Container( width: 100, height: 100, color: Colors.pink, ), ); }, ), SizedBox(height: 200), Text(BounceOut 曲线), ], ), ), ); } override void dispose() { _controller.dispose(); super.dispose(); } }五、组合动画class CombinedAnimationExample extends StatefulWidget { override _CombinedAnimationExampleState createState() _CombinedAnimationExampleState(); } class _CombinedAnimationExampleState extends StateCombinedAnimationExample with SingleTickerProviderStateMixin { late AnimationController _controller; late Animationdouble _scaleAnimation; late Animationdouble _opacityAnimation; late AnimationOffset _positionAnimation; override void initState() { super.initState(); _controller AnimationController( duration: Duration(seconds: 1), vsync: this, ); _scaleAnimation Tweendouble(begin: 0.5, end: 1.0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeOut), ); _opacityAnimation Tweendouble(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeIn), ); _positionAnimation TweenOffset( begin: Offset(-1, 0), end: Offset(0, 0), ).animate( CurvedAnimation(parent: _controller, curve: Curves.bounceOut), ); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(组合动画)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SlideTransition( position: _positionAnimation, child: FadeTransition( opacity: _opacityAnimation, child: ScaleTransition( scale: _scaleAnimation, child: Container( width: 200, height: 200, decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue, Colors.purple], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), ), child: Center( child: Text( 组合动画, style: TextStyle(color: Colors.white, fontSize: 18), ), ), ), ), ), ), SizedBox(height: 24), ElevatedButton( onPressed: () { _controller.forward(from: 0); }, child: Text(开始动画), ), ], ), ), ); } override void dispose() { _controller.dispose(); super.dispose(); } }六、性能优化使用 const 构造器减少不必要的重建合理使用 AnimatedBuilder只重建需要动画的部分避免在动画回调中做耗时操作保持动画流畅使用 RepaintBoundary隔离重绘区域七、最佳实践保持简洁避免过度复杂的动画使用合适的时长根据动画类型选择合适的时长测试性能在低端设备上测试动画流畅度考虑可访问性为减少动画偏好的用户提供降级方案动画是界面的灵魂让用户体验更加生动有趣。#flutter #animation #ui #dart #frontend

更多文章