又要用Compose来做Loading了,不过这次是带小火苗的
本篇文章已同步更新至个人公众号:Coffeeee
今年第一篇Compose动效开发,继续回归老本行,来一起做个Loading,老实说Loading动效个人已经做麻了,去年做了十几个,这次主要是想实现一个带火苗的Loading,因为之前看到过有位博主用Threejs实现过一个火焰的效果,然后又是职业病啊,想试试看用Compose实现一个火焰效果到底难不难
扩散效果
第一步,先别去想啥Loading,先想想火是啥样子的,颜色以红黄为主,也有蓝色的,绿色的,然后从火源开始逐渐向外燃烧扩散,那么这里首先就要想办法把扩散的效果做出来,先上基础代码
先创建出代表画布的宽高width
和height
,Canvas
创建出来之后会得到宽高的具体值,然后宽高的一半就是画布的中心坐标centerx
与centery
,radius
是整个Loading
的半径,接着我们先随意在中心位置画一个实心圆
现在如果想要让这个实心圆动起来的话,通常会使用animateFloatAsState
这个api,比如这里想要改变它的横坐标,可以这么写
也可以使用循环动画让圆点在那一直动
但是以上两种方式如果是作用在有限数量的视图上,是没啥问题的,但是像我们要做的这个扩散效果,有大量元素的,并且每个元素动画的轨迹方向都不一样,那么就不能使用上面这种动画api了,性能问题先不说,写起来也是个麻烦,所以得想个其他办法,那么既然不能用动画api来改变元素的位置,我们就手动改嘛,先来定义个model,代表每个元素,这个model有以下几个属性
其中
startX
:代表元素初始位置的x坐标startY
:代表元素初始位置的y坐标endx
:代表元素移动结束后的x坐标endy
:代表元素移动结束后的y坐标angle
:代表元素移动的方向,也就是角度dis
:代表元素每次移动的距离size
:代表元素的大小,如果是圆就当作半径,如果是方块就当作宽高color
:代表元素的颜色
然后给Particle
里面添加一些更新位置的代码,第一处在初始化函数中,目的是当Particle
刚创建出来时候,根据startX
与startY
来计算出第一次位移的终点endx
与endy
pointX
与pointY
分别是通过起点,角度,半径来计算终点坐标的函数,代码如下
除了刚才在初始化函数中加的代码之外,还要增加一个update
函数,每次调用这个函数的时候,都会重新把上一次的终点作为起点,重新计算新的终点坐标,这样才能做到让元素移动的效果
这样我们Particle
的基础功能就开发完成了,接下来就要去创建我们需要扩散的元素,由于数量较多,我们得循环创建这些元素才行,首先创建的事情我们放在副作用函数LaunchedEffect
中进行
其中ANGLES
表示0到360的一个范围,调用random()
函数来随机取出一个值当作元素移动的方向角度,上述代码中还缺点东西,首先需要有一个数组来保存创建好之后的Particle
,我们这里新建一个数组,将创建好之后的Particle
添加到数组中
其次这个LaunchedEffect
函数体由于key
是true
,所以无论重组几次都只会执行一次,那么我们的元素只会创建一次,而我们想要的效果是每过10毫秒都创建个元素,所以得把key
值改成一个会改变的值,只有key
改变了才会触发LaunchedEffect
再执行一遍内部的代码,那么这个key我们就改成particleList
这个数组的大小,每创建一个新元素,particleList
的大小都会改变,改变之后下一次又会重新再去创建新元素,代码修改为
现在每过10毫秒,我们就会多一个Particle
元素,但是现在只是创建了元素,元素还没动起来,要让它们动起来的话这个时候就要用到之前我们创建的update
函数了,我们在重组的过程中遍历particleList
中的元素,每个元素都执行一遍update
,这样元素就动起来了
整个扩散效果到这里就算完工了,来看看效果咋样
定制扩散的样式
扩散的效果做出来了,但是可以看到现在是无限往四周扩散的,咱要做的火苗可不能无限扩散,那不得发大火了吗,所以得让我们这些元素扩散到一定范围之后“看不见”,在Canvas
中让一个元素看不见除了不去绘制之外,就是让它的透明度为0,那么在Particle
中再新增一个属性alpha
来表示元素的透明度
默认值为1,然后在update
函数中,每次都减去一点透明值,直到透明值变为0,那么该元素就看不见了
在Canvas
中drawCircle
函数中也添加alpha
属性
现在这个扩散的范围看起来又太小了,不过没事,可以通过设置dis
属性来增加整个扩散的区域
还可以给每个元素设置不同的大小和颜色来改变整个效果的外观,先创建个半径的范围
再创建个颜色的集合
然后在创建Particle
的时候,随机从半径范围与颜色集合中取出一个值作为Particle
的size
和color
再来看下现在的效果
制作loading效果
到这里为止我们的扩散的起始为止都是一个固定的点,现在要让这个固定的点变成可以变化的,绕着圆周转圈,那么首先就要获得圆周上的角度,这里使用循环动画创建一个0到360度循环改变的值当成角度
获得角度之后,使用pointX
跟pointY
函数来计算出这个角度在圆周上的x坐标tapx
与y坐标tapy
,将创建元素用到的centerx
与centery
替换成tapx
,tapy
现在扩散效果就绕着画布中心转圈了
看起来有点别扭啊,首先这个转圈一顿一顿的,然后尾巴貌似分叉的太开了,不过没事,这些都可以优化,分叉的太开主要是我们扩散的角度是0到360度,将这个范围变小一点就好了
动画一顿一顿的是因为我们的动画设置的是两秒,它只有到了两秒以后才会进行下一次动画,但是变化的角度不到两秒的时候就已经到达360度了,所以才会在360度的位置停滞了一段时间,解决办法就是将动画规格从补间动画改成关键帧动画,将到达360度的那一帧设置在2000毫秒的位置上
转圈不顿了,但是现在离火苗的效果还是有点出入的,我们这个loading的头部位置相当于火苗的燃烧源头,而燃烧源相对来讲都是比较大的,然后逐渐朝着燃烧的方向变小,所以还得继续优化下,现在元素的半径还太小,得变大
其次在update
函数中,也对半径size
做递减处理,直到半径变为0
再来看下效果
还差最后一步,将整个画布设置下模糊效果,设置一下blur
函数,内部参数越大,模糊的效果越严重,调了一下后7.dp
比较合适
加了模糊效果后的效果如下
一团小火苗就做出来了,感觉效果比较空,我们可以再加一个火苗,现在圆周上只有一个定点在转,我们再加一个,颜色设置成偏蓝,刚好一个火焰一个冰焰
最终效果如下
总结
到这里一个火焰Loading的动效就完成了,还是很容易的其实,里面最主要的就是通过那几个参数来控制好元素扩散的效果,甚至我们可以尝试着去更改一些参数或者实现方式,来做一些其他不一样的动效,这些大家如果有兴趣的可以自己去试试看。
来源:juejin.cn/post/7329433979806810146