前言
基本用法
实现原理
在前面实践组件的开发中,我们做了一个登录的界面,里面有一个组件Hero,不知道大家是否记得?当时没有展开来说,是因为它属于动画的内容,本文就要重点讲解Hero动画。
做过Java开发Android的程序员应该都清楚,Shared Element Transition可以让Activity或Fragment做出流畅的动画,同样,在Flutter开发中,Hero动画也能实现类似的效果。简单来说,Hero的作用就是在路由之间做出流畅的转场动画。
Hero组件的用法是需要同时定义源组件和目标组件,其中源组件和目标组件被Hero包裹在需要动画控制的组件外面,如果有一方不指定,在有些情况下,界面就会卡死,我们先来看看它的基本用法,首先是main.dart代码:
代码很简单,就是监听点击事件ontap,hero包裹FlutterLogo组件,然后点击跳转到第二个界面。接着我们再来看看第二个页面CustomFlutterLogo.dart的代码:
这段代码也很简单,就是常用的组件,只是在外层套了一层Hero动画组件,不过这里有一点我们需要注意,hero里面有一个tag属性,必须写上,不然会报错,不信的读者,可以删除后运行试试。
我们基本已经掌握了Hero路由跳转动画的用法,但我们不能只看表面,不明其原理,因为后面讲解的动画也会涉及到这些知识,所以我们必须掌握。
Hero动画,它的整个运动过程分为3个步骤,即动画开始(t=0.0),动画进行中,动画结束(t=1.0),下面是Hero动画运动示意图:
如上图所示,两个路由之间还有一个Overlay层。在动画开始时,Flutter会计算出Hero的位置并复制一份,然后绘制到Overlay层上。复制的Hero和源Hero的大小是一致的,并且该Hero是在所有路由之上。在动画实现的过程中,Flutter会逐渐把源Hero移除屏幕。在动画进行中Flutter是依靠Tween来实现,通过createRectTween属性把Tween传给Hero。Hero内部默认使用MeterialRectArcTween的曲线路径进行移动动画的操作。在动画结束时,Flutter将Overlay中的Hero移除,且完成了Hero在目标路由上的显示,这时Overlay是空白的。
Hero中所有变换都是通过HeroController来实现的,HeroController是在MeterialApp中通过initState和didUpdateWidget方法来完成初始化的,源码如下所示:
在初始化HeroController时,Flutter携带了一个参数,就是_createRectTween,该参数返回的默认项就是MaterialRectArcTween。Flutter源码里还为我们实现了第二种RectTween返回值,即MaterialRectCenterArcTween。由此可见,可以对createRectTween进行自定义。我们再看看HeroController的具体内容,代码如下:
HeroController其实继承的是NavigatorObserver。在路由操作的didPush和didPop回调方法里,可以调用_maybeStartHeroTransition,并通过WidgetsBinding把源路由,目标路由,HeroController关联起来。在使用didPush和didPop回调时,通过调用_startHeroTransition方法让Hero动起来,只不过前者是正向的,后者是逆向的。