AnimationController动画基础_Flutter在鸿蒙平台实现流畅UI动画
作者:付文龙(红目香薰)
仓库地址:https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com
概述
Flutter动画系统是一个强大的动画框架,它基于Animation和AnimationController实现流畅的UI动画效果。Flutter动画系统的核心特点:
- 声明式动画:通过状态驱动动画,无需手动管理帧更新
- 高性能:基于GPU渲染,60fps流畅动画
- 灵活:支持各种动画类型和曲线
- 组合性:可以组合多个动画实现复杂效果
动画的重要性
- 用户体验提升:动画使界面更加生动和流畅
- 交互反馈:提供视觉反馈,增强用户操作感知
- 引导用户:通过动画引导用户注意力
- 品牌个性:独特的动画风格可以体现品牌特色
核心概念
Animation
Animation是Flutter动画的核心抽象类,它代表一个随时间变化的值。动画的值可以是任意类型:double、Color、Offset等。
AnimationController
AnimationController是Animation的子类,用于控制动画的播放、暂停、反向、重复等操作。
Tween
Tween用于定义数值的插值范围,将动画的进度值(0-1)映射到实际的数值范围。
CurvedAnimation
CurvedAnimation用于添加曲线效果,使动画更加自然。
AnimatedBuilder
AnimatedBuilder是一个Widget,用于监听动画变化并重建UI。
实现步骤
第一步:创建AnimationController
首先创建一个AnimationController,需要指定vsync和duration。
classAnimationDemoextendsStatefulWidget{constAnimationDemo({super.key});@overrideState<AnimationDemo>createState()=>_AnimationDemoState();}class_AnimationDemoStateextendsState<AnimationDemo>withSingleTickerProviderStateMixin{lateAnimationController_controller;@overridevoidinitState(){super.initState();_controller=AnimationController(vsync:this,duration:constDuration(seconds:2),);}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:Center(child:AnimatedBuilder(animation:_controller,builder:(context,child){returnContainer(width:_controller.value*300,height:_controller.value*300,color:Colors.blue,);},),),floatingActionButton:FloatingActionButton(onPressed:()=>_controller.forward(),child:constIcon(Icons.play_arrow),),);}}第二步:使用Tween插值
使用Tween定义数值的插值范围。
// 数值插值Animation<double>sizeAnimation=Tween<double>(begin:0,end:300).animate(_controller);// 颜色插值Animation<Color>colorAnimation=ColorTween(begin:Colors.blue,end:Colors.red,).animate(_controller);// 边框插值Animation<BorderRadius>borderRadiusAnimation=BorderRadiusTween(begin:BorderRadius.circular(0),end:BorderRadius.circular(50),).animate(_controller);// 位置插值Animation<Offset>offsetAnimation=Tween<Offset>(begin:constOffset(0,0),end:constOffset(100,100),).animate(_controller);第三步:使用CurvedAnimation
使用CurvedAnimation添加曲线效果。
Animation<double>curvedAnimation=CurvedAnimation(parent:_controller,curve:Curves.easeInOut,);Animation<double>sizeAnimation=Tween<double>(begin:0,end:300).animate(curvedAnimation);第四步:在AnimatedBuilder中使用动画
AnimatedBuilder(animation:_animation,builder:(context,child){returnContainer(width:_animation.value,height:_animation.value,color:Colors.blue,);},)AnimationController方法
基本控制方法
_controller.forward();// 正向播放(从0到1)_controller.reverse();// 反向播放(从1到0)_controller.reset();// 重置到初始状态(值为0)_controller.repeat();// 重复播放_controller.stop();// 停止播放_controller.animateTo(0.5);// 动画到指定值(0-1)_controller.animateBack(0.5);// 反向动画到指定值属性设置
_controller.duration=constDuration(seconds:1);// 设置动画时长_controller.reverseDuration=constDuration(seconds:1);// 设置反向时长_controller.value=0.5;// 设置当前值_controller.lowerBound=0;// 设置下限_controller.upperBound=1;// 设置上限_controller.isAnimating;// 是否正在播放_controller.status;// 当前状态动画状态
AnimationStatus.dismissed;// 动画在起始位置(值为0)AnimationStatus.forward;// 动画正向播放中AnimationStatus.reverse;// 动画反向播放中AnimationStatus.completed;// 动画在结束位置(值为1)监听动画
监听值变化
_controller.addListener((){setState((){});});监听状态变化
_controller.addStatusListener((status){if(status==AnimationStatus.completed){_controller.reverse();}elseif(status==AnimationStatus.dismissed){_controller.forward();}});常用曲线
Flutter提供了多种内置曲线,使动画更加自然。
| 曲线名称 | 效果 | 适用场景 |
|---|---|---|
Curves.linear | 线性变化 | 匀速动画 |
Curves.ease | 缓入 | 开始缓慢,然后加速 |
Curves.easeIn | 缓入 | 开始缓慢 |
Curves.easeOut | 缓出 | 结束缓慢 |
Curves.easeInOut | 缓入缓出 | 开始和结束都缓慢 |
Curves.bounceIn | 弹跳进入 | 弹跳效果 |
Curves.bounceOut | 弹跳退出 | 弹跳效果 |
Curves.elasticIn | 弹性进入 | 弹性效果 |
Curves.elasticOut | 弹性退出 | 弹性效果 |
Curves.fastOutSlowIn | 快速开始,缓慢结束 | Material Design标准 |
组合动画
多个动画同步
classComboAnimationextendsStatefulWidget{constComboAnimation({super.key});@overrideState<ComboAnimation>createState()=>_ComboAnimationState();}class_ComboAnimationStateextendsState<ComboAnimation>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_sizeAnimation;lateAnimation<Color>_colorAnimation;lateAnimation<double>_opacityAnimation;@overridevoidinitState(){super.initState();_controller=AnimationController(vsync:this,duration:constDuration(seconds:2),);_sizeAnimation=Tween<double>(begin:50,end:200).animate(_controller);_colorAnimation=ColorTween(begin:Colors.blue,end:Colors.red).animate(_controller);_opacityAnimation=Tween<double>(begin:0.3,end:1).animate(_controller);_controller.repeat(reverse:true);}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnAnimatedBuilder(animation:_controller,builder:(context,child){returnOpacity(opacity:_opacityAnimation.value,child:Container(width:_sizeAnimation.value,height:_sizeAnimation.value,color:_colorAnimation.value,borderRadius:BorderRadius.circular(_sizeAnimation.value/4),),);},);}}动画延迟
Animation<double>delayedAnimation=Tween<double>(begin:0,end:100).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.5,1.0),),);动画性能优化
使用AnimatedBuilder
AnimatedBuilder只会重建builder中的内容,不会重建整个Widget树。
AnimatedBuilder(animation:_animation,builder:(context,child){returnContainer(width:_animation.value,height:_animation.value,child:child,);},child:constText('Hello'),)使用AnimatedWidget
AnimatedWidget是一个抽象类,可以继承它创建自定义动画Widget。
classAnimatedContainerextendsAnimatedWidget{constAnimatedContainer({super.key,requiredAnimation<double>animation,}):super(listenable:animation);@overrideWidgetbuild(BuildContextcontext){finalanimation=listenableasAnimation<double>;returnContainer(width:animation.value,height:animation.value,color:Colors.blue,);}}使用AnimatedOpacity、AnimatedContainer等
Flutter提供了许多预定义的动画Widget。
AnimatedOpacity(opacity:_opacity,duration:constDuration(seconds:1),child:constText('Hello'),)AnimatedContainer(width:_width,height:_height,color:_color,duration:constDuration(seconds:1),)AnimatedPositioned(left:_left,top:_top,duration:constDuration(seconds:1),child:constText('Hello'),)Hero动画
Hero动画用于页面间的共享元素过渡。
// 源页面Hero(tag:'image',child:Image.network('https://example.com/image.jpg'),)// 目标页面Hero(tag:'image',child:Image.network('https://example.com/image.jpg'),)自定义曲线
创建自定义曲线
classCustomCurveextendsCurve{@overridedoubletransform(double t){returnt*t;}}Animation<double>customAnimation=CurvedAnimation(parent:_controller,curve:CustomCurve(),);使用曲线组合
Animation<double>combinedAnimation=CurvedAnimation(parent:_controller,curve:Curves.easeIn.flipped,);完整示例
弹跳按钮动画
import'package:flutter/material.dart';voidmain(){runApp(constMaterialApp(home:BounceButtonDemo()));}classBounceButtonDemoextendsStatefulWidget{constBounceButtonDemo({super.key});@overrideState<BounceButtonDemo>createState()=>_BounceButtonDemoState();}class_BounceButtonDemoStateextendsState<BounceButtonDemo>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_scaleAnimation;lateAnimation<double>_opacityAnimation;@overridevoidinitState(){super.initState();_controller=AnimationController(vsync:this,duration:constDuration(milliseconds:500),);_scaleAnimation=Tween<double>(begin:1,end:0.8).animate(CurvedAnimation(parent:_controller,curve:Curves.bounceIn,),);_opacityAnimation=Tween<double>(begin:1,end:0.5).animate(_controller);}@overridevoiddispose(){_controller.dispose();super.dispose();}void_onPressed(){_controller.forward().then((_){_controller.reverse();});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText("弹跳按钮动画")),body:Center(child:AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:_scaleAnimation.value,child:Opacity(opacity:_opacityAnimation.value,child:ElevatedButton(onPressed:_onPressed,style:ElevatedButton.styleFrom(padding:constEdgeInsets.symmetric(horizontal:40,vertical:16),textStyle:constTextStyle(fontSize:20),),child:constText("点击弹跳"),),),);},),),);}}最佳实践
1. 使用SingleTickerProviderStateMixin
SingleTickerProviderStateMixin提供vsync,确保动画在Widget可见时才运行。
class_MyWidgetStateextendsState<MyWidget>withSingleTickerProviderStateMixin{lateAnimationController_controller;}2. 在dispose中释放资源
@overridevoiddispose(){_controller.dispose();super.dispose();}3. 使用AnimatedBuilder避免不必要的重建
AnimatedBuilder(animation:_animation,builder:(context,child){returnContainer(width:_animation.value);},child:constText('不变的内容'),)4. 优先使用预定义的动画Widget
AnimatedOpacity(...)AnimatedContainer(...)AnimatedPositioned(...)5. 使用曲线使动画更自然
CurvedAnimation(parent:_controller,curve:Curves.easeInOut,)6. 组合多个动画时使用同一个Controller
_sizeAnimation=Tween(begin:50,end:200).animate(_controller);_colorAnimation=ColorTween(begin:Colors.blue,end:Colors.red).animate(_controller);总结
Flutter动画系统是一个强大而灵活的动画框架,通过AnimationController、Tween、CurvedAnimation和AnimatedBuilder等组件,可以实现各种复杂的动画效果。
核心要点:
- 使用
AnimationController控制动画的播放、暂停、反向等 - 使用
Tween定义数值的插值范围 - 使用
CurvedAnimation添加曲线效果 - 使用
AnimatedBuilder监听动画变化并重建UI - 在
dispose中释放AnimationController资源
通过合理使用Flutter动画系统,可以创建出流畅、自然的用户界面,提升用户体验。