源码:https://github.com/coffeetang/myloading
作者:Coffeeee
链接:https://juejin.cn/post/7252171495819903036
圆弧和圆
这个动效想不出叫啥,就随意叫了个,整个动画过程还是蛮简单的,分两部分,一部分是两个圆弧绕着圆心做圆周运动,速度由快变慢,另一部分是中心有一个空心圆,空心圆的半径在做变长变短的循环运动,所以基本用两个循环动画就能完成,首先我们需要定义动画需要用到的变量
centerX
与centerY
是动画的圆心坐标,radius
是绘制两个圆弧的半径,然后我们再创建一个循环动画,循环的值是0度到360度
这里我们速度的变化是使用的FastOutSlowInEasing
,为的就是让圆弧转圈的速度有个由快变慢的过程,接下来就在Canvas
中将两个圆弧画出来
就是画了两个扇形,然后startAngle
加上了angleDiff
的变化值,两个圆弧就能转起来了,效果如下
接下来就是中间变大变小的圆,那也是个循环过程,我们再创建一个循环动画,循环的范围在20f到60f的区间来回变化
circleSize
就是我们绘制中间圆的半径,最终的效果如下
转圈的小球
这个动效跟上一个有一点相同的地方,那就是小球在绕着圆心转圈的时候,小球与圆心的距离也是在一个区间范围里循环变化的,所以仍旧需要创建个循环动画,其次不同的是小球在转圈时候,不是一直绕着圆心转,而是当小球在远离圆心的时候转个角度,再接近圆心的时候,三个小球是不转的,这里我们采用的做法是做个动画间的时间差,分析好了以后还是老规矩,先创建必要的变量
圆周运动少不了的中心点centerX
与centerY
,anglist
是绘制小球的角度,ballradius
是每个球的半径,colorList
是小球的颜色,首先创建个循环动画,动画的区间范围我们定义为半个小球半径到四倍小球半径,代码如下
radiusDiff
就是小球与画布中心的间距,通过pointX
与pointY
计算出某个角度小球本身的圆心坐标,最后用drawCircle
函数将小球绘制出来,pointX
与pointY
的代码如下
这个时候小球就能实现与画布中心距离变化的动画了,看下效果
接着是让小球转动起来,并且是在小球远离中心的时候才转动,接近中心的时候不转,要实现这个的话刚才我们说了就是利用一个时间差,我们知道radiusDiff
变化的时间是单个方向500毫秒,所以小球单次转动时间也是500毫秒,然后下一次转动的时间就要在小球转动的时间上再加500毫秒,因为小球还有接近圆心的过程,所以这里用一个Flow来做一个定时器,定时触发小球转动
diff
每过一秒就递增90度的角度,angleDiff
就是这个角度递增的动画过程,我们将angleDiff
这个变量添加到计算小球球心的过程中,最终整个小球的动画效果就完成了
又是转圈的小球
再做个转圈小球的动效,但是这里小球与中心的距离就不变了,是个定值,变得是啥呢?变得是小球自身的半径以及透明值,所达到的效果希望是小球在转圈的时候,自身的半径由小变大然后在变小,透明值也是由浅变深再变浅,那么先将这个动效需要的变量准备好
centerX
与centerY
是画布的中心点,radius
是小球做圆周运动的半径大小,radiusList
是小球自身需要变化的半径,然后既然是自身的半径由小变大然后在变小,透明值由浅变深再变浅,那么这个就是个循环过程了,我们需要创建两个循环动画,并且repeatMode
要定义成Reverse
index
就是不断变化的半径List的下标值,alphaDiff
就是不断变化的透明值,那么我们可以先画出两个不转圈的,但是半径与透明值都会变化的小球了
然后就是要让小球绕着中心转起来,这个也是个循环动画,角度就是从0到180度,主要是动画时间要注意下,由于之前半径与透明值单次变化过程我们设置为1秒,然后因为这两个动画是Reverse
的,所以完整的动画下来是用时两秒,所以我们小球绕着中心转圈的动画也需要设置为两秒
然后将绘制圆用到的角度换成angDiff
,注意两个圆设置的角度必须是相反数,这样转圈时候才可以绕着相反方向转圈
这样一个完整的动效就做好了,看下最终版
跳动的心
这个动效需要考虑两部分,如何画一个爱心和如何让爱心跳动起来,一个爱心如果单纯的想一笔画出来,可能没有这样的api提供给我们,但是可以脑补一下,如果将一个爱心从中间分隔开来,那是不是就等于画两个三阶贝塞尔曲线呢,所以我们第一步就要确定好贝塞尔曲线的控制点,我们如果将画布分割成3 * 3的网格布局,那么我们的控制点就在下面这几个位置
知道了控制点的位置,我们就能将两个曲线的Path
创建出来
再绘制到画布上以后,我们就得到了一个红色的爱心
爱心画出来了以后就得考虑下如何让爱心跳动起来,跳动其实就是改变一下绘制爱心用到的控制点的坐标,如果所有控制点在一个坐标区间里面循环改变的话,那么看起来这个爱心就有个跳动的效果,所以先创建个循环动画,动画的改变范围是0f到15f
然后将这个改变值diff
代入到创建Path
的对应坐标里面,代入后的代码如下
现在再运行一下后,就得到了一颗跳动的心了
给心加点颜色的渐变,让心看起来能够稍微立体一些,就得到了最后的效果
七彩螺旋
这个效果最主要的就是知道如何画一个螺旋,其实螺旋就是若干个,圆心离中心点逐渐变大,转动的角度也逐渐变大的圆组合起来的样子,所以要画螺旋的话,首先就得要有所有半径以及转动的角度
radiusList
存放着所有与圆心的距离,anglist
保存着所有转动的角度,我们可以通过遍历任何一个数组,获取角度以及与圆心的距离,然后计算出对应圆点的中心坐标值,等所有圆点画完之后,就是我们要的螺旋
pointX
与pointY
我们已经熟悉了,就是计算圆点中心坐标的函数,不多讲了,运行后得到一个静止的螺旋样式
然后我们得让这个螺旋转起来,这个也简单,让每一个圆点角度不断增加一个0到360变化的值,那么整体螺旋就转起来了,先创建一个0到360循环动画
然后再将每个圆点的角度加上变化值diff
,螺旋就转起来了
然后就是给螺旋染色了,染色的方式也是通过遍历一个色值的数组,然后从数组里面不断拿出颜色显示在螺旋上,显示的时候我们再用animateColorAsState
函数给颜色与颜色切换的时候加上一个动画过渡的效果,这部分的代码如下
这里同样也是创建了一个下标遍历的循环过程colorIndex
,然后用colorIndex
从颜色数组colorList
中获取颜色,最终我们将colorSet
设置到螺旋后的效果如下
辐射效果
这个效果是之前无意中看到一个辐射的标志牌,然后在这个样式的基础上做了个修改得到的,一般性辐射的标志样式都是中间一个圆,然后四周三个扇形围绕着这个圆,像下面这个图一样
我们这里稍作修改,将实心扇形用几个扇形圆弧来代替,并且每秒钟从最里面的圆弧朝外变换颜色,中间的圆展示的颜色也与圆弧展示的颜色保持一致,整体也是在顺时针转动,首先创建需要用到的变量
colorList
是要展示的颜色色值,radiusList
是绘制所有圆弧的半径大小,anglist
用来保存需要转动的角度,通过这些我们可以将圆点与所有圆弧画出来,代码如下
一个辐射标志就出来了,现在要让这个标志转起来,我们在第一个动效里面就做过类似的事情,要让圆弧转起来那么就是不断改变startAngle
的值,而anglist
里面保存的就是所有需要转动的角度值,我们只需要不断从anglist
里面拿出对应角度加到startAngle
上就好了
angleIndex
就是一个anglist
下标值不断循环变化的动画过程,然后再更改下绘制圆弧的代码,让startAngle
加上对应下标值的角度值,就得到了一个会转动的辐射标志
然后就是给圆弧以及圆点染色,这里也给colorList
的下标值创建一个循环动画过程colorIndex
,让colorIndex
与圆弧半径相同的圆弧才能亮起对应的颜色,并且稍微加粗一点,其余圆弧依然是白色,这个过程的代码如下
中间的圆球也要改变颜色,当圆弧亮起哪种色值的时候,圆球也展示同样的色值,那么这个简单了,因为我们有colorIndex
,只需要给圆球设置colorIndex
对应的色值就好了
最终效果如下
浮动的n * n圆点图
这个效果是在一个n * n的网格布局里面,画(n-1) * (n-1)个圆点,然后逐个去改变每个圆点的大小,首先我们先将这些圆点画出来
xUnit
和yUnit
为横纵方向上单元格子的大小,而每个圆点的半径radius
就是这俩值的最小值的三分之一,然后再创建两个存放每个圆点中心x坐标与y坐标的List,分别为xList
与yList
,最后再遍历这里啊list之后,画出所有的圆点
画完点之后,就要想一下如何让这些点浮动起来,既然是浮动,那肯定是几个点同时动起来看起来才像是浮动,所以得找出这些同时动的点,我们先看下下面的图
这图啥意思呢?意思就是每一根斜线经过的圆点就是需要同时动的,这些点之间也存在着一个规律,那就是从第一根斜线开始,所经过的点的xy坐标相加是一个固定的值,然后每一根线依次下去,这个值都会增加1,比如第一根线的点,xy坐标相加为0,第二根斜线的点,xy相加为1,最后一根线的点,xy相加的值就为(n-1)+(n-1),然后我们就能在遍历list的时候,通过判断xIndex
与yIndex
相加为某一个值来划分圆点动画的最大范围,在我们demo中是一个4 * 4的圆点图,那么所有斜线上圆点相加的值的范围就是0到6,我们可以通过一个循环动画来循环找出当前动画的最大范围在哪一个值上,再让每一个点的xy坐标相加的值与最大范围的值相减,得到的值取绝对值再除上10,那就是每一个点的缩放大小比例,如果得到的值大于1,那就保持不变,啰嗦了那么多,其实代码没多少,我们看下
我们看到target
就是创建出来的循环动画,得到的值就是当前最大范围的值,在循环体中与每一个点的xy坐标相加得到的temp
进行相减,最终得到的tempAlpha
就是点的缩放比例,在绘制圆点的时候,将这个缩放比例作用在半径与透明值上,我们最终的浮动动效就完成了
跳动的小球
这个动效是将画布分成若干份,每一份都有上下两个小球,上面的小球逐渐缩小自己的y轴高度,下面的小球逐渐增加y轴高度,这个过程也是循环的,首先创建需要用的变量
xList
就是所有小球的x坐标,colorList
就是所有小球的色值,然后在画布中将上下两排小球画出来
看到第二排小球带了点渐变和透明,为的是让第二排小球看起来有点像第一排小球的倒影一样,得到的效果如下
现在我们让小球动起来,也就是在y坐标上加上一个无限变化的值,代码如下
创建了一个0f到60f无限变化的动画过程diffIndex
,然后在遍历xList
的过程中,将diffIndex
与index * 10f
相减,得到的值的绝对值就是小球高度的变化值,效果如下
转圈的彩虹
这个效果是之前在网上看见别人用CSS实现了一个,彩虹的话之前我也画过,但是转圈的而且每个弧转动的速率还不一样的彩虹还没画过,所以这里也准备用Compose来实现一个试试看,先将画彩虹需要的变量创建出来
singleWidth
是单个彩虹弧的宽度,gap
是彩虹弧之间的间距,colorList
是所有彩虹的颜色,circleRdius
是最大彩虹弧的半径,然后就能遍历colorList
来把七个彩虹弧画出来了
接下来是让彩虹转起来,让圆弧转动的操作我们已经做了很多遍了,就是无限改变startAngle
的值,所以这里再创建一个0到360无限改变动画过程
然后再把start
传到drawArc
的startAngle
参数里去,彩虹就能动起来了
动起来了以后,就要在上面加点效果了,现在每条彩虹弧都是同时开始旋转的,用的都是start
的动画值,现在我们想让最外面的先转,接着是第二个,然后第三个以此类推,那么这个时候每一条彩虹弧都需要一个动画变量了,这里再创建六个
可以看到,新增的六个动画变量与最先创建的那个唯一的不同点就是多了个延迟启动的参数,然后总的动画时间都是1500毫秒,这样就能保证每个彩虹弧启动时机不同,但是都是同时结束旋转的,我们把这些新增的动画变量添加到绘制彩虹的代码中
这里已经根据不同的下标值使用不同的动画变量了,我们再看下效果
可以看到由于添加了延迟时间,每个彩虹弧的启动时间都不同了,那么再加个效果,有延迟那么也会有走过头的效果,我们让每个彩虹弧在结束转圈的时候,都会有个超出最终值的过程,然后再回到最终目标值,怎么做呢?我们需要将InfiniteRepeatableSpec
里面的AnimationSpec
从TweenSpec
换成KeyframeSpec
,然后KeyframeSpec
可以设置在动画时间内的某一个时间点,到达一个比目标值还要大的值,然后在动画时间结束的时候,在到达最终目标值,所以我们将刚刚七个动画变量更改一下
每个动画现在都设置了KeyframeSpec
了,现在再看看效果
总结
这些动效有的是网上看见别人用CSS实现,然后自己用Compose复制了一个,有的是自己没事琢磨出来的,这几个都没用Modifier
提供的动画操作符去实现,都是用的Canvas
加Compose的动画api去做的,相信如果看完这篇和上一篇文章的小伙伴,在Compose的项目中如果遇到那些不是太复杂的动画需求的时候,都可以不用问设计师要切图,自己去用代码实现了,靠谁不如靠自己是不?
关注我获取更多知识或者投稿