作者:付文龙(红目香薰)
仓库地址:https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com
概述
在Flutter动画开发中,AnimatedWidget和AnimatedBuilder是两种重要的动画组件复用方式。它们都能够帮助开发者将动画逻辑与UI代码分离,提高代码的复用性和可维护性。
AnimatedWidget核心概念
什么是AnimatedWidget
AnimatedWidget是一个抽象类,它继承自StatefulWidget,用于封装动画逻辑。通过继承AnimatedWidget,可以将动画相关的代码抽取到一个独立的组件中,实现动画逻辑的复用。
创建AnimatedWidget
classFadeWidgetextendsAnimatedWidget{constFadeWidget({super.key,requiredAnimation<double>animation,requiredthis.child,}):super(listenable:animation);finalWidgetchild;Animation<double>get_animation=>listenableasAnimation<double>;@overrideWidgetbuild(BuildContextcontext){returnOpacity(opacity:_animation.value,child:child,);}}AnimatedWidget的使用
classAnimatedWidgetExampleextendsStatefulWidget{constAnimatedWidgetExample({super.key});@overrideState<AnimatedWidgetExample>createState()=>_AnimatedWidgetExampleState();}class_AnimatedWidgetExampleStateextendsState<AnimatedWidgetExample>withSingleTickerProviderStateMixin{lateAnimationController_controller;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);_controller.repeat(reverse:true);}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('AnimatedWidget示例')),body:Center(child:FadeWidget(animation:_controller,child:constFlutterLogo(size:200),),),);}}AnimatedBuilder核心概念
什么是AnimatedBuilder
AnimatedBuilder是一个便捷的动画构建器,它接收一个builder回调函数,在动画值变化时重新构建UI。AnimatedBuilder不需要创建新类,可以直接在代码中使用。
创建AnimatedBuilder
AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:0.5+_controller.value*0.5,child:child,);},child:constFlutterLogo(size:200),)AnimatedBuilder的使用
classAnimatedBuilderExampleextendsStatefulWidget{constAnimatedBuilderExample({super.key});@overrideState<AnimatedBuilderExample>createState()=>_AnimatedBuilderExampleState();}class_AnimatedBuilderExampleStateextendsState<AnimatedBuilderExample>withSingleTickerProviderStateMixin{lateAnimationController_controller;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);_controller.repeat(reverse:true);}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('AnimatedBuilder示例')),body:Center(child:AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:0.5+_controller.value*0.5,child:child,);},child:constFlutterLogo(size:200),),),);}}AnimatedWidget与AnimatedBuilder对比
| 特性 | AnimatedWidget | AnimatedBuilder |
|---|---|---|
| 创建方式 | 需要创建新类 | 直接使用builder回调 |
| 复用性 | 高,适合通用动画组件 | 低,适合一次性使用 |
| 代码量 | 较多 | 较少 |
| 适用场景 | 通用动画组件封装 | 临时动画效果 |
| 性能 | 需要创建新组件实例 | 直接回调,更轻量 |
| 灵活性 | 固定的动画逻辑 | 灵活的动画逻辑 |
使用AnimatedBuilder优化性能
传递child参数
将不变的子Widget传递给child参数,可以避免不必要的重建:
AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:_scaleAnimation.value,child:child,);},child:constFlutterLogo(size:100),)组合多个动画
AnimatedBuilder可以方便地组合多个动画:
AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.translate(offset:Offset(_slideAnimation.value,0),child:Opacity(opacity:_fadeAnimation.value,child:child,),);},child:constFlutterLogo(size:100),)使用AnimatedWidget封装通用组件
封装淡入动画组件
classFadeInAnimationextendsAnimatedWidget{constFadeInAnimation({super.key,requiredAnimation<double>animation,requiredthis.child,}):super(listenable:animation);finalWidgetchild;Animation<double>get_animation=>listenableasAnimation<double>;@overrideWidgetbuild(BuildContextcontext){returnOpacity(opacity:_animation.value,child:child,);}}封装缩放动画组件
classScaleAnimationextendsAnimatedWidget{constScaleAnimation({super.key,requiredAnimation<double>animation,requiredthis.child,}):super(listenable:animation);finalWidgetchild;Animation<double>get_animation=>listenableasAnimation<double>;@overrideWidgetbuild(BuildContextcontext){returnTransform.scale(scale:_animation.value,child:child,);}}复杂动画场景
组合AnimatedWidget
classComplexAnimationextendsStatefulWidget{constComplexAnimation({super.key});@overrideState<ComplexAnimation>createState()=>_ComplexAnimationState();}class_ComplexAnimationStateextendsState<ComplexAnimation>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_fadeAnimation;lateAnimation<double>_scaleAnimation;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);_fadeAnimation=CurvedAnimation(parent:_controller,curve:Curves.easeInOut);_scaleAnimation=Tween<double>(begin:0.5,end:1).animate(CurvedAnimation(parent:_controller,curve:Curves.easeOut),);_controller.repeat(reverse:true);}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('复杂动画组合')),body:Center(child:FadeInAnimation(animation:_fadeAnimation,child:ScaleAnimation(animation:_scaleAnimation,child:constFlutterLogo(size:200),),),),);}}使用AnimatedBuilder实现复杂动画
classComplexAnimatedBuilderextendsStatefulWidget{constComplexAnimatedBuilder({super.key});@overrideState<ComplexAnimatedBuilder>createState()=>_ComplexAnimatedBuilderState();}class_ComplexAnimatedBuilderStateextendsState<ComplexAnimatedBuilder>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_rotationAnimation;lateAnimation<double>_scaleAnimation;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:3),vsync:this,);_rotationAnimation=Tween<double>(begin:0,end:2*pi).animate(CurvedAnimation(parent:_controller,curve:Curves.linear),);_scaleAnimation=Tween<double>(begin:0.5,end:1.5).animate(CurvedAnimation(parent:_controller,curve:Curves.easeInOut),);_controller.repeat();}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('复杂AnimatedBuilder')),body:Center(child:AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.rotate(angle:_rotationAnimation.value,child:Transform.scale(scale:_scaleAnimation.value,child:child,),);},child:constFlutterLogo(size:200),),),);}}性能优化最佳实践
使用AnimatedBuilder避免重建
// 不推荐:每次动画都会重建FlutterLogoAnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:_controller.value,child:constFlutterLogo(size:100),);},)// 推荐:FlutterLogo只创建一次AnimatedBuilder(animation:_controller,builder:(context,child){returnTransform.scale(scale:_controller.value,child:child,);},child:constFlutterLogo(size:100),)使用RepaintBoundary隔离重绘
AnimatedBuilder(animation:_controller,builder:(context,child){returnRepaintBoundary(child:Transform.scale(scale:_controller.value,child:child,),);},child:constFlutterLogo(size:100),)鸿蒙平台注意事项
在鸿蒙平台使用AnimatedWidget和AnimatedBuilder时,需要注意以下几点:
- 组件创建开销:
AnimatedWidget每次创建都会产生组件实例开销,对于简单动画优先使用AnimatedBuilder - 性能测试:在鸿蒙真机上测试复杂动画的流畅度
- 资源释放:确保
AnimationController在dispose方法中正确释放 - 动画复杂度:避免在动画回调中进行大量计算
总结
AnimatedWidget和AnimatedBuilder是Flutter动画系统中两种重要的复用方式。AnimatedWidget适合封装通用的动画组件,具有较高的复用性;AnimatedBuilder适合快速实现临时动画效果,更加轻量灵活。在实际开发中,应根据具体场景选择合适的方式,并注意性能优化,确保动画在鸿蒙平台上流畅运行。