用Compose又做了几个loading,有你喜欢的吗?

3,196 阅读15分钟

通过上一篇文章的简单学习,我们已经初步学会了如何使用Compose来制作Loading动效,那么为了巩固这部分的知识点,这一篇文章我们继续用Compose来做几个loading动效加深印象,篇幅较长,可以选取感兴趣的动效来看

源码地址

圆弧和圆

这个动效想不出叫啥,就随意叫了个,整个动画过程还是蛮简单的,分两部分,一部分是两个圆弧绕着圆心做圆周运动,速度由快变慢,另一部分是中心有一个空心圆,空心圆的半径在做变长变短的循环运动,所以基本用两个循环动画就能完成,首先我们需要定义动画需要用到的变量

image.png

centerXcenterY是动画的圆心坐标,radius是绘制两个圆弧的半径,然后我们再创建一个循环动画,循环的值是0度到360度

image.png

这里我们速度的变化是使用的FastOutSlowInEasing,为的就是让圆弧转圈的速度有个由快变慢的过程,接下来就在Canvas中将两个圆弧画出来

image.png

就是画了两个扇形,然后startAngle加上了angleDiff的变化值,两个圆弧就能转起来了,效果如下

0703aa1.gif

接下来就是中间变大变小的圆,那也是个循环过程,我们再创建一个循环动画,循环的范围在20f到60f的区间来回变化

image.png

circleSize就是我们绘制中间圆的半径,最终的效果如下

0703aa2.gif

转圈的小球

这个动效跟上一个有一点相同的地方,那就是小球在绕着圆心转圈的时候,小球与圆心的距离也是在一个区间范围里循环变化的,所以仍旧需要创建个循环动画,其次不同的是小球在转圈时候,不是一直绕着圆心转,而是当小球在远离圆心的时候转个角度,再接近圆心的时候,三个小球是不转的,这里我们采用的做法是做个动画间的时间差,分析好了以后还是老规矩,先创建必要的变量

image.png

圆周运动少不了的中心点centerXcenterY,anglist是绘制小球的角度,ballradius是每个球的半径,colorList是小球的颜色,首先创建个循环动画,动画的区间范围我们定义为半个小球半径到四倍小球半径,代码如下

image.png

radiusDiff就是小球与画布中心的间距,通过pointXpointY计算出某个角度小球本身的圆心坐标,最后用drawCircle函数将小球绘制出来,pointXpointY的代码如下

image.png

这个时候小球就能实现与画布中心距离变化的动画了,看下效果

0703aa3.gif

接着是让小球转动起来,并且是在小球远离中心的时候才转动,接近中心的时候不转,要实现这个的话刚才我们说了就是利用一个时间差,我们知道radiusDiff变化的时间是单个方向500毫秒,所以小球单次转动时间也是500毫秒,然后下一次转动的时间就要在小球转动的时间上再加500毫秒,因为小球还有接近圆心的过程,所以这里用一个Flow来做一个定时器,定时触发小球转动

image.png

diff每过一秒就递增90度的角度,angleDiff就是这个角度递增的动画过程,我们将angleDiff这个变量添加到计算小球球心的过程中,最终整个小球的动画效果就完成了

image.png 0703aa4.gif

又是转圈的小球

再做个转圈小球的动效,但是这里小球与中心的距离就不变了,是个定值,变得是啥呢?变得是小球自身的半径以及透明值,所达到的效果希望是小球在转圈的时候,自身的半径由小变大然后在变小,透明值也是由浅变深再变浅,那么先将这个动效需要的变量准备好

image.png

centerXcenterY是画布的中心点,radius是小球做圆周运动的半径大小,radiusList是小球自身需要变化的半径,然后既然是自身的半径由小变大然后在变小,透明值由浅变深再变浅,那么这个就是个循环过程了,我们需要创建两个循环动画,并且repeatMode要定义成Reverse

image.png

index就是不断变化的半径List的下标值,alphaDiff就是不断变化的透明值,那么我们可以先画出两个不转圈的,但是半径与透明值都会变化的小球了

image.png 0705aa1.gif

然后就是要让小球绕着中心转起来,这个也是个循环动画,角度就是从0到180度,主要是动画时间要注意下,由于之前半径与透明值单次变化过程我们设置为1秒,然后因为这两个动画是Reverse的,所以完整的动画下来是用时两秒,所以我们小球绕着中心转圈的动画也需要设置为两秒

image.png

然后将绘制圆用到的角度换成angDiff,注意两个圆设置的角度必须是相反数,这样转圈时候才可以绕着相反方向转圈

image.png

这样一个完整的动效就做好了,看下最终版

0705aa2.gif

跳动的心

这个动效需要考虑两部分,如何画一个爱心和如何让爱心跳动起来,一个爱心如果单纯的想一笔画出来,可能没有这样的api提供给我们,但是可以脑补一下,如果将一个爱心从中间分隔开来,那是不是就等于画两个三阶贝塞尔曲线呢,所以我们第一步就要确定好贝塞尔曲线的控制点,我们如果将画布分割成3 * 3的网格布局,那么我们的控制点就在下面这几个位置

image.png

知道了控制点的位置,我们就能将两个曲线的Path创建出来

image.png

再绘制到画布上以后,我们就得到了一个红色的爱心

image.png image.png

爱心画出来了以后就得考虑下如何让爱心跳动起来,跳动其实就是改变一下绘制爱心用到的控制点的坐标,如果所有控制点在一个坐标区间里面循环改变的话,那么看起来这个爱心就有个跳动的效果,所以先创建个循环动画,动画的改变范围是0f到15f

image.png

然后将这个改变值diff代入到创建Path的对应坐标里面,代入后的代码如下

image.png

现在再运行一下后,就得到了一颗跳动的心了

0703aa5.gif

给心加点颜色的渐变,让心看起来能够稍微立体一些,就得到了最后的效果

image.png 0703aa6.gif

七彩螺旋

这个效果最主要的就是知道如何画一个螺旋,其实螺旋就是若干个,圆心离中心点逐渐变大,转动的角度也逐渐变大的圆组合起来的样子,所以要画螺旋的话,首先就得要有所有半径以及转动的角度

image.png

radiusList存放着所有与圆心的距离,anglist保存着所有转动的角度,我们可以通过遍历任何一个数组,获取角度以及与圆心的距离,然后计算出对应圆点的中心坐标值,等所有圆点画完之后,就是我们要的螺旋

image.png

pointXpointY我们已经熟悉了,就是计算圆点中心坐标的函数,不多讲了,运行后得到一个静止的螺旋样式

image.png

然后我们得让这个螺旋转起来,这个也简单,让每一个圆点角度不断增加一个0到360变化的值,那么整体螺旋就转起来了,先创建一个0到360循环动画

image.png

然后再将每个圆点的角度加上变化值diff,螺旋就转起来了

image.png

0703aa9.gif

然后就是给螺旋染色了,染色的方式也是通过遍历一个色值的数组,然后从数组里面不断拿出颜色显示在螺旋上,显示的时候我们再用animateColorAsState函数给颜色与颜色切换的时候加上一个动画过渡的效果,这部分的代码如下

image.png

这里同样也是创建了一个下标遍历的循环过程colorIndex,然后用colorIndex从颜色数组colorList中获取颜色,最终我们将colorSet设置到螺旋后的效果如下

image.png

0704aa1.gif

辐射效果

这个效果是之前无意中看到一个辐射的标志牌,然后在这个样式的基础上做了个修改得到的,一般性辐射的标志样式都是中间一个圆,然后四周三个扇形围绕着这个圆,像下面这个图一样

fushe.png

我们这里稍作修改,将实心扇形用几个扇形圆弧来代替,并且每秒钟从最里面的圆弧朝外变换颜色,中间的圆展示的颜色也与圆弧展示的颜色保持一致,整体也是在顺时针转动,首先创建需要用到的变量

image.png

colorList是要展示的颜色色值,radiusList是绘制所有圆弧的半径大小,anglist用来保存需要转动的角度,通过这些我们可以将圆点与所有圆弧画出来,代码如下

image.png image.png

一个辐射标志就出来了,现在要让这个标志转起来,我们在第一个动效里面就做过类似的事情,要让圆弧转起来那么就是不断改变startAngle的值,而anglist里面保存的就是所有需要转动的角度值,我们只需要不断从anglist里面拿出对应角度加到startAngle上就好了

image.png

angleIndex就是一个anglist下标值不断循环变化的动画过程,然后再更改下绘制圆弧的代码,让startAngle加上对应下标值的角度值,就得到了一个会转动的辐射标志

image.png 0703aa7.gif

然后就是给圆弧以及圆点染色,这里也给colorList的下标值创建一个循环动画过程colorIndex,让colorIndex与圆弧半径相同的圆弧才能亮起对应的颜色,并且稍微加粗一点,其余圆弧依然是白色,这个过程的代码如下

image.png

中间的圆球也要改变颜色,当圆弧亮起哪种色值的时候,圆球也展示同样的色值,那么这个简单了,因为我们有colorIndex,只需要给圆球设置colorIndex对应的色值就好了

image.png

最终效果如下

0703aa8.gif

浮动的n * n圆点图

这个效果是在一个n * n的网格布局里面,画(n-1) * (n-1)个圆点,然后逐个去改变每个圆点的大小,首先我们先将这些圆点画出来

image.png

xUnityUnit为横纵方向上单元格子的大小,而每个圆点的半径radius就是这俩值的最小值的三分之一,然后再创建两个存放每个圆点中心x坐标与y坐标的List,分别为xListyList,最后再遍历这里啊list之后,画出所有的圆点

image.png

image.png

画完点之后,就要想一下如何让这些点浮动起来,既然是浮动,那肯定是几个点同时动起来看起来才像是浮动,所以得找出这些同时动的点,我们先看下下面的图

image.png

这图啥意思呢?意思就是每一根斜线经过的圆点就是需要同时动的,这些点之间也存在着一个规律,那就是从第一根斜线开始,所经过的点的xy坐标相加是一个固定的值,然后每一根线依次下去,这个值都会增加1,比如第一根线的点,xy坐标相加为0,第二根斜线的点,xy相加为1,最后一根线的点,xy相加的值就为(n-1)+(n-1),然后我们就能在遍历list的时候,通过判断xIndexyIndex相加为某一个值来划分圆点动画的最大范围,在我们demo中是一个4 * 4的圆点图,那么所有斜线上圆点相加的值的范围就是0到6,我们可以通过一个循环动画来循环找出当前动画的最大范围在哪一个值上,再让每一个点的xy坐标相加的值与最大范围的值相减,得到的值取绝对值再除上10,那就是每一个点的缩放大小比例,如果得到的值大于1,那就保持不变,啰嗦了那么多,其实代码没多少,我们看下

image.png

我们看到target就是创建出来的循环动画,得到的值就是当前最大范围的值,在循环体中与每一个点的xy坐标相加得到的temp进行相减,最终得到的tempAlpha就是点的缩放比例,在绘制圆点的时候,将这个缩放比例作用在半径与透明值上,我们最终的浮动动效就完成了

0704aa2.gif

跳动的小球

这个动效是将画布分成若干份,每一份都有上下两个小球,上面的小球逐渐缩小自己的y轴高度,下面的小球逐渐增加y轴高度,这个过程也是循环的,首先创建需要用的变量

image.png

xList就是所有小球的x坐标,colorList就是所有小球的色值,然后在画布中将上下两排小球画出来

image.png

看到第二排小球带了点渐变和透明,为的是让第二排小球看起来有点像第一排小球的倒影一样,得到的效果如下

image.png

现在我们让小球动起来,也就是在y坐标上加上一个无限变化的值,代码如下

image.png

创建了一个0f到60f无限变化的动画过程diffIndex,然后在遍历xList的过程中,将diffIndexindex * 10f相减,得到的值的绝对值就是小球高度的变化值,效果如下

0704aa3.gif

转圈的彩虹

这个效果是之前在网上看见别人用CSS实现了一个,彩虹的话之前我也画过,但是转圈的而且每个弧转动的速率还不一样的彩虹还没画过,所以这里也准备用Compose来实现一个试试看,先将画彩虹需要的变量创建出来

image.png

singleWidth是单个彩虹弧的宽度,gap是彩虹弧之间的间距,colorList是所有彩虹的颜色,circleRdius是最大彩虹弧的半径,然后就能遍历colorList来把七个彩虹弧画出来了

image.png image.png

接下来是让彩虹转起来,让圆弧转动的操作我们已经做了很多遍了,就是无限改变startAngle的值,所以这里再创建一个0到360无限改变动画过程

image.png

然后再把start传到drawArcstartAngle参数里去,彩虹就能动起来了

image.png 0704aa4.gif

动起来了以后,就要在上面加点效果了,现在每条彩虹弧都是同时开始旋转的,用的都是start的动画值,现在我们想让最外面的先转,接着是第二个,然后第三个以此类推,那么这个时候每一条彩虹弧都需要一个动画变量了,这里再创建六个

image.png

可以看到,新增的六个动画变量与最先创建的那个唯一的不同点就是多了个延迟启动的参数,然后总的动画时间都是1500毫秒,这样就能保证每个彩虹弧启动时机不同,但是都是同时结束旋转的,我们把这些新增的动画变量添加到绘制彩虹的代码中

image.png

这里已经根据不同的下标值使用不同的动画变量了,我们再看下效果

0704aa5.gif

可以看到由于添加了延迟时间,每个彩虹弧的启动时间都不同了,那么再加个效果,有延迟那么也会有走过头的效果,我们让每个彩虹弧在结束转圈的时候,都会有个超出最终值的过程,然后再回到最终目标值,怎么做呢?我们需要将InfiniteRepeatableSpec里面的AnimationSpecTweenSpec换成KeyframeSpec,然后KeyframeSpec可以设置在动画时间内的某一个时间点,到达一个比目标值还要大的值,然后在动画时间结束的时候,在到达最终目标值,所以我们将刚刚七个动画变量更改一下

image.png

每个动画现在都设置了KeyframeSpec了,现在再看看效果

0704aa6.gif

总结

这些动效有的是网上看见别人用CSS实现,然后自己用Compose复制了一个,有的是自己没事琢磨出来的,这几个都没用Modifier提供的动画操作符去实现,都是用的Canvas加Compose的动画api去做的,相信如果看完这篇和上一篇文章的小伙伴,在Compose的项目中如果遇到那些不是太复杂的动画需求的时候,都可以不用问设计师要切图,自己去用代码实现了,靠谁不如靠自己是不?