作者:付文龙(红目香薰)
仓库地址:https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com
概述
Staggered动画(交错动画)是一种将多个动画按照时间顺序依次执行或部分重叠执行的动画技术。它能够创造出富有层次感和节奏感的视觉效果,是现代UI设计中常用的动画手法。
Staggered动画核心概念
什么是Staggered动画
Staggered动画指的是多个动画按照一定的时间间隔依次开始,形成一种波浪式的视觉效果。这种动画方式能够引导用户的注意力,增强界面的交互体验。
Interval时间间隔
在Flutter中,实现Staggered动画的核心是Interval类,它定义了动画执行的时间范围:
Interval(double begin,double end,{Curvecurve=Curves.linear})begin:动画开始时间占总时长的比例(0.0-1.0)end:动画结束时间占总时长的比例(0.0-1.0)curve:动画曲线
基础Staggered动画实现
创建交错淡入动画
classStaggeredFadeAnimationextendsStatefulWidget{constStaggeredFadeAnimation({super.key});@overrideState<StaggeredFadeAnimation>createState()=>_StaggeredFadeAnimationState();}class_StaggeredFadeAnimationStateextendsState<StaggeredFadeAnimation>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_fadeAnimation1;lateAnimation<double>_fadeAnimation2;lateAnimation<double>_fadeAnimation3;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);_fadeAnimation1=Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.0,0.3,curve:Curves.easeOut),),);_fadeAnimation2=Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.2,0.6,curve:Curves.easeOut),),);_fadeAnimation3=Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.4,1.0,curve:Curves.easeOut),),);_controller.forward();}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('交错淡入动画')),body:Column(mainAxisAlignment:MainAxisAlignment.center,children:[FadeTransition(opacity:_fadeAnimation1,child:constFlutterLogo(size:100)),constSizedBox(height:20),FadeTransition(opacity:_fadeAnimation2,child:constFlutterLogo(size:100)),constSizedBox(height:20),FadeTransition(opacity:_fadeAnimation3,child:constFlutterLogo(size:100)),],),);}}复杂Staggered动画组合
组合多种动画效果
classComplexStaggeredAnimationextendsStatefulWidget{constComplexStaggeredAnimation({super.key});@overrideState<ComplexStaggeredAnimation>createState()=>_ComplexStaggeredAnimationState();}class_ComplexStaggeredAnimationStateextendsState<ComplexStaggeredAnimation>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_fadeAnimation;lateAnimation<double>_slideAnimation;lateAnimation<double>_scaleAnimation;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);_fadeAnimation=Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.0,0.3,curve:Curves.easeOut),),);_slideAnimation=Tween<double>(begin:-50,end:0).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.2,0.6,curve:Curves.easeOut),),);_scaleAnimation=Tween<double>(begin:0.5,end:1).animate(CurvedAnimation(parent:_controller,curve:constInterval(0.4,1.0,curve:Curves.easeOut),),);_controller.forward();}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('复杂交错动画')),body:Center(child:AnimatedBuilder(animation:_controller,builder:(context,child){returnOpacity(opacity:_fadeAnimation.value,child:Transform.translate(offset:Offset(_slideAnimation.value,0),child:Transform.scale(scale:_scaleAnimation.value,child:constFlutterLogo(size:200),),),);},),),);}}列表交错动画
动态列表项动画
classStaggeredListAnimationextendsStatefulWidget{constStaggeredListAnimation({super.key});@overrideState<StaggeredListAnimation>createState()=>_StaggeredListAnimationState();}class_StaggeredListAnimationStateextendsState<StaggeredListAnimation>{finalList<String>items=List.generate(10,(index)=>'Item${index+1}');@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('列表交错动画')),body:ListView.builder(itemCount:items.length,itemBuilder:(context,index){returnStaggeredListItem(index:index,text:items[index]);},),);}}classStaggeredListItemextendsStatefulWidget{finalint index;finalStringtext;constStaggeredListItem({super.key,requiredthis.index,requiredthis.text});@overrideState<StaggeredListItem>createState()=>_StaggeredListItemState();}class_StaggeredListItemStateextendsState<StaggeredListItem>withSingleTickerProviderStateMixin{lateAnimationController_controller;lateAnimation<double>_animation;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(milliseconds:500),vsync:this,);_animation=Tween<double>(begin:100,end:0).animate(CurvedAnimation(parent:_controller,curve:Curves.easeOut),);Future.delayed(Duration(milliseconds:widget.index*100),(){_controller.forward();});}@overridevoiddispose(){_controller.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnAnimatedBuilder(animation:_animation,builder:(context,child){returnTransform.translate(offset:Offset(_animation.value,0),child:ListTile(title:Text(widget.text)),);},);}}Staggered动画进阶技巧
使用StaggeredAnimationBuilder
虽然Flutter没有内置的StaggeredAnimationBuilder,但可以封装一个:
classStaggeredAnimationBuilderextendsStatefulWidget{finalint count;finalDurationduration;finalDurationdelay;finalWidgetFunction(int index,Animation<double>animation)builder;constStaggeredAnimationBuilder({super.key,requiredthis.count,requiredthis.duration,requiredthis.delay,requiredthis.builder,});@overrideState<StaggeredAnimationBuilder>createState()=>_StaggeredAnimationBuilderState();}class_StaggeredAnimationBuilderStateextendsState<StaggeredAnimationBuilder>{List<Animation<double>>_animations=[];List<AnimationController>_controllers=[];@overridevoidinitState(){super.initState();_animations=[];_controllers=[];for(int i=0;i<widget.count;i++){AnimationControllercontroller=AnimationController(duration:widget.duration,vsync:this,);Animation<double>animation=Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:controller,curve:Curves.easeOut),);_controllers.add(controller);_animations.add(animation);Future.delayed(widget.delay*i,(){controller.forward();});}}@overridevoiddispose(){for(varcontrollerin_controllers){controller.dispose();}super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnColumn(children:List.generate(widget.count,(index){returnwidget.builder(index,_animations[index]);}),);}}交互式Staggered动画
classInteractiveStaggeredAnimationextendsStatefulWidget{constInteractiveStaggeredAnimation({super.key});@overrideState<InteractiveStaggeredAnimation>createState()=>_InteractiveStaggeredAnimationState();}class_InteractiveStaggeredAnimationStateextendsState<InteractiveStaggeredAnimation>withSingleTickerProviderStateMixin{lateAnimationController_controller;@overridevoidinitState(){super.initState();_controller=AnimationController(duration:constDuration(seconds:2),vsync:this,);}@overridevoiddispose(){_controller.dispose();super.dispose();}void_playAnimation(){_controller.reset();_controller.forward();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('交互式交错动画')),body:Column(children:[Expanded(child:StaggeredAnimationBuilder(count:5,duration:constDuration(milliseconds:500),delay:constDuration(milliseconds:100),builder:(index,animation){returnFadeTransition(opacity:animation,child:FlutterLogo(size:80+index*20),);},),),ElevatedButton(onPressed:_playAnimation,child:constText('播放动画')),],),);}}Staggered动画性能优化
避免过度绘制
对于大量列表项的交错动画,使用RepaintBoundary减少重绘:
AnimatedBuilder(animation:_animation,builder:(context,child){returnRepaintBoundary(child:Transform.translate(offset:Offset(_animation.value,0),child:child,),);},child:constListTile(title:Text('Item')),)复用AnimationController
对于简单的交错动画,可以考虑复用AnimationController:
_controller=AnimationController(duration:constDuration(milliseconds:500*itemCount),vsync:this,);for(int i=0;i<itemCount;i++){animations.add(Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent:_controller,curve:Interval(i/itemCount,(i+1)/itemCount,curve:Curves.easeOut,),),));}鸿蒙平台测试建议
在鸿蒙平台测试Staggered动画时,建议关注以下几点:
- 动画同步:验证多个动画的时间间隔是否准确
- 性能表现:大量列表项动画的流畅度
- 内存使用:长时间运行动画的内存占用
- 动画重置:多次播放动画的正确性
总结
Staggered动画是一种强大的动画技术,能够创造出富有层次感的视觉效果。通过Interval类定义动画的时间范围,可以精确控制多个动画的执行顺序。在实际应用中,Staggered动画常用于列表项入场、页面元素依次显示等场景。掌握Staggered动画的实现方式,能够为应用增添更加生动的交互体验。