ConstraintLayout2.0一篇写不完之Stagger交错
共 4306字,需浏览 9分钟
·
2021-09-08 10:05
点击上方蓝字关注我,知识会给你力量
在Flutter中,有个StaggerAnimation,可以实现交错动画效果,这个效果相当于在申明式编程中为多个动画增加了多条时间线,在Android中,以往要实现交错动画效果,需要为每个属性动画设置Delay时间,或者监听其生命周期,而在MotionLayout中,可以直接在xml中设置交错动画的驱动流程,极大的简化了动画的创建。
在MotionLayout中,它为每个被标记了motionStagger的View分配了一个float value(没有标记的View不会被引入交错动画),float value最小的(V0)的View首先被启动。float value最高的(Vn)的View最后启动。
这是motionStagger的动画总纲,但是具体的启动时间和执行顺序,由下面的这些参数来精确控制。
MotionLayout中每个VIew的motionStagger value被标记为S(Vi) 总的Stagger Value被标记为stagger,取值为0.0-1.0,通常在Transition中指定 在Transition中指定动画的duration
在这基础上,motionStagger定义了下面两条规则:
View的动画持续时长 = duration * (1 - stagger) View的动画启动时间点算法为:duration * (stagger - stagger * (S(Vi) - S(V0)) / (S(Vn) - S(V0)))
其中最奇怪的就是这个参数:(S(Vi) - S(V0)) / (S(Vn) - S(V0))
我们可以梳理下,我们给MotionLayout中的所有需要做StaggerAnimation的View标记了motionStagger value,这些元素形成了一个数组,从大到小进行排序:
【Sv0—Sv1—Sv2—Sv3—Sv4—Sv5】
在这个数组只,(S(Vi) - S(V0)) / (S(Vn) - S(V0))这个表达式所具有的几何含义是什么呢?实际上就是点阵的Manhattan distance(曼哈顿距离),具体如下所示。
好了,看到这里还不走的朋友,心里也忍不住会想了,这TM是什么鬼?我写个动画还TM要这些??
是的,有的复杂,我们先举个例子来看下。
首先,我假定设置MotionLayout中有3个View——View1、View2、View3,分别设置motionStagger value为7,5,3,再给Transition设置staggered为0.6,duration为5000,这些都是我假设的,我们来看下这个状态下,MotionLayout的StaggerAnimation是如何创建的。
首先,计算duration。
View的动画持续时长 = duration * (1 - stagger)
即:View的动画持续时长 = 5000 * (1 - 0.6) = 2000
接下来,针对每个View计算,所以,Sv1= 7,Sv2= 5,Sv3= 3。
duration * (stagger - stagger * (S(Vi) - S(V0)) / (S(Vn) - S(V0)))
即:
View1:启动于 5000 * (0.6 - 0.6 * (7 - 3)/(7 - 3)) = 0
终止于 0 + 2000 = 2000
View2:启动于 5000 * (0.6 - 0.6 * (5 - 3)/(7 - 3)) = 1500
终止于 1500 + 2000 = 3500
View3:启动于 5000 * (0.6 - 0.6 * (3 - 3)/(7 - 3)) = 3000
终止于 3000 + 2000 = 5000
是不是有点意思。
我感觉没意思,难道我写动画还要这样凑数字吗?
如果我们要从正向来理解这些公式的含义,那么要将上面的公式进行一下变形处理。
startPoint = duration * (stagger - stagger * (S(Vi) - S(V0)) / (S(Vn) - S(V0)))
再理清楚一点:
animationStartTime = totalDuration * (stagger - stagger * ((staggerCurrentView - lowestStaggerValue)/(highestStaggerValue - lowestStaggerValue))
totalDuration好说,剩下的就是stagger值的确定了。
我们同样用之前那个例子,我假定设置MotionLayout中有3个View——View1、View2、View3,三个View依次出现。
前面我们的公式指出了:viewDuration = totalDuration * (1 - stagger),那么将其变形处理后,我们就得到了stagger:
stagger = 1 - (viewDuration / totalDuration)
所以,如果我要三个动画依次出现,那么viewDuration / totalDuration就是1/3,也就是说stagger约为0.6。
确定了stagger之后,我们再来看duration,由于stagger确定,所以totalDuration可以自由设置,viewDuration会根据其它两个参数动态变化。
那么每个View的motionStagger呢?实际上在开发动画的时候,通常都是先使用递减数列或者递增数列来做(取决于你的视图展示顺序),再根据动画参数进行微调,例如前面的例子,我们可以给View1、2、3分别设置motionStagger为3、2、1,那么启动顺序如下所示。
totalDuration = 5000,stagger = 0.6,viewDuration = 2000
即:
View1:启动于 5000 * (0.6 - 0.6 * (3 - 1)/(3 - 1)) = 0
终止于 0 + 2000 = 2000
View2:启动于 5000 * (0.6 - 0.6 * (2 - 1)/(3 - 1)) = 1500
终止于 1500 + 2000 = 3500
View3:启动于 5000 * (0.6 - 0.6 * (1 - 1)/(3 - 1)) = 3000
终止于 3000 + 2000 = 5000
有没有发现,和前面的结果是一致的!
越来越难了不是吗,写个动画还得用这么多数学公式!
其实不用。
最后我们来总结下,一句话让你了解Stagger。
❝当MotionLayout中的所有View的motionStagger value递增或者递减时,在Transition中设置的staggered控制的就是每个View启动的时间间隔,staggered value越小,间隔越短,极端下,为0时,没有Stagger效果,为1时,每个View动画完成后才执行下一个。
❞
以上。
当然,你不懂这些公式也能写,但是懂了能让你写的更清晰,这就是「凑」和「算」的区别。
向大家推荐下我的网站 https://xuyisheng.top/ 点击原文一键直达
专注 Android-Kotlin-Flutter 欢迎大家访问
往期推荐
更文不易,点个“三连”支持一下👇