又要用Compose来做Loading了,不过这次是带小火苗的

本篇文章已同步更新至个人公众号:Coffeeee

今年第一篇Compose动效开发,继续回归老本行,来一起做个Loading,老实说Loading动效个人已经做麻了,去年做了十几个,这次主要是想实现一个带火苗的Loading,因为之前看到过有位博主用Threejs实现过一个火焰的效果,然后又是职业病啊,想试试看用Compose实现一个火焰效果到底难不难

源码地址

扩散效果

第一步,先别去想啥Loading,先想想火是啥样子的,颜色以红黄为主,也有蓝色的,绿色的,然后从火源开始逐渐向外燃烧扩散,那么这里首先就要想办法把扩散的效果做出来,先上基础代码

先创建出代表画布的宽高widthheightCanvas创建出来之后会得到宽高的具体值,然后宽高的一半就是画布的中心坐标centerxcentery,radius是整个Loading的半径,接着我们先随意在中心位置画一个实心圆

现在如果想要让这个实心圆动起来的话,通常会使用animateFloatAsState这个api,比如这里想要改变它的横坐标,可以这么写

也可以使用循环动画让圆点在那一直动

但是以上两种方式如果是作用在有限数量的视图上,是没啥问题的,但是像我们要做的这个扩散效果,有大量元素的,并且每个元素动画的轨迹方向都不一样,那么就不能使用上面这种动画api了,性能问题先不说,写起来也是个麻烦,所以得想个其他办法,那么既然不能用动画api来改变元素的位置,我们就手动改嘛,先来定义个model,代表每个元素,这个model有以下几个属性

其中

  • startX:代表元素初始位置的x坐标
  • startY:代表元素初始位置的y坐标
  • endx:代表元素移动结束后的x坐标
  • endy:代表元素移动结束后的y坐标
  • angle:代表元素移动的方向,也就是角度
  • dis:代表元素每次移动的距离
  • size:代表元素的大小,如果是圆就当作半径,如果是方块就当作宽高
  • color:代表元素的颜色

然后给Particle里面添加一些更新位置的代码,第一处在初始化函数中,目的是当Particle刚创建出来时候,根据startXstartY来计算出第一次位移的终点endxendy

pointXpointY分别是通过起点,角度,半径来计算终点坐标的函数,代码如下

除了刚才在初始化函数中加的代码之外,还要增加一个update函数,每次调用这个函数的时候,都会重新把上一次的终点作为起点,重新计算新的终点坐标,这样才能做到让元素移动的效果

这样我们Particle的基础功能就开发完成了,接下来就要去创建我们需要扩散的元素,由于数量较多,我们得循环创建这些元素才行,首先创建的事情我们放在副作用函数LaunchedEffect中进行

其中ANGLES表示0到360的一个范围,调用random()函数来随机取出一个值当作元素移动的方向角度,上述代码中还缺点东西,首先需要有一个数组来保存创建好之后的Particle,我们这里新建一个数组,将创建好之后的Particle添加到数组中

其次这个LaunchedEffect函数体由于keytrue,所以无论重组几次都只会执行一次,那么我们的元素只会创建一次,而我们想要的效果是每过10毫秒都创建个元素,所以得把key值改成一个会改变的值,只有key改变了才会触发LaunchedEffect再执行一遍内部的代码,那么这个key我们就改成particleList这个数组的大小,每创建一个新元素,particleList的大小都会改变,改变之后下一次又会重新再去创建新元素,代码修改为

现在每过10毫秒,我们就会多一个Particle元素,但是现在只是创建了元素,元素还没动起来,要让它们动起来的话这个时候就要用到之前我们创建的update函数了,我们在重组的过程中遍历particleList中的元素,每个元素都执行一遍update,这样元素就动起来了

整个扩散效果到这里就算完工了,来看看效果咋样

定制扩散的样式

扩散的效果做出来了,但是可以看到现在是无限往四周扩散的,咱要做的火苗可不能无限扩散,那不得发大火了吗,所以得让我们这些元素扩散到一定范围之后"看不见",在Canvas中让一个元素看不见除了不去绘制之外,就是让它的透明度为0,那么在Particle中再新增一个属性alpha来表示元素的透明度

默认值为1,然后在update函数中,每次都减去一点透明值,直到透明值变为0,那么该元素就看不见了

CanvasdrawCircle函数中也添加alpha属性

现在这个扩散的范围看起来又太小了,不过没事,可以通过设置dis属性来增加整个扩散的区域

还可以给每个元素设置不同的大小和颜色来改变整个效果的外观,先创建个半径的范围

再创建个颜色的集合

然后在创建Particle的时候,随机从半径范围与颜色集合中取出一个值作为Particlesizecolor

再来看下现在的效果

制作loading效果

到这里为止我们的扩散的起始为止都是一个固定的点,现在要让这个固定的点变成可以变化的,绕着圆周转圈,那么首先就要获得圆周上的角度,这里使用循环动画创建一个0到360度循环改变的值当成角度

获得角度之后,使用pointXpointY函数来计算出这个角度在圆周上的x坐标tapx与y坐标tapy,将创建元素用到的centerxcentery替换成tapx,tapy

现在扩散效果就绕着画布中心转圈了

看起来有点别扭啊,首先这个转圈一顿一顿的,然后尾巴貌似分叉的太开了,不过没事,这些都可以优化,分叉的太开主要是我们扩散的角度是0到360度,将这个范围变小一点就好了

动画一顿一顿的是因为我们的动画设置的是两秒,它只有到了两秒以后才会进行下一次动画,但是变化的角度不到两秒的时候就已经到达360度了,所以才会在360度的位置停滞了一段时间,解决办法就是将动画规格从补间动画改成关键帧动画,将到达360度的那一帧设置在2000毫秒的位置上

转圈不顿了,但是现在离火苗的效果还是有点出入的,我们这个loading的头部位置相当于火苗的燃烧源头,而燃烧源相对来讲都是比较大的,然后逐渐朝着燃烧的方向变小,所以还得继续优化下,现在元素的半径还太小,得变大

其次在update函数中,也对半径size做递减处理,直到半径变为0

再来看下效果

还差最后一步,将整个画布设置下模糊效果,设置一下blur函数,内部参数越大,模糊的效果越严重,调了一下后7.dp比较合适

加了模糊效果后的效果如下

一团小火苗就做出来了,感觉效果比较空,我们可以再加一个火苗,现在圆周上只有一个定点在转,我们再加一个,颜色设置成偏蓝,刚好一个火焰一个冰焰

最终效果如下

总结

到这里一个火焰Loading的动效就完成了,还是很容易的其实,里面最主要的就是通过那几个参数来控制好元素扩散的效果,甚至我们可以尝试着去更改一些参数或者实现方式,来做一些其他不一样的动效,这些大家如果有兴趣的可以自己去试试看。

相关推荐
每天开心9 分钟前
别再怕 useRef 了!一篇文章讲清楚它和 DOM 的关系
前端·面试·前端框架
小喷友9 分钟前
第 2 章:页面与路由系统
前端·react.js·next.js
Java水解11 分钟前
前端绘图基础——SVG详解
前端·svg
在钱塘江12 分钟前
《你不知道的JavaScript-中卷》第一部分-类型和语法-笔记-3-原生函数
前端·javascript
帅夫帅夫16 分钟前
Vue2 Diff算法详解 - 双端比较的奥秘
前端
阿琳a_20 分钟前
解决vue中使用vite-plugin-cesium插件打包后运行项目报错
前端·javascript·vue.js·vite·cesium
前端岳大宝23 分钟前
React条件渲染
前端·react.js·前端框架
用户68238060322528 分钟前
Ant Design v5 不兼容 React 19,导致 message.xxx() 内部渲染逻辑没有生效(也就是弹不出消息框)。
前端
BER_c31 分钟前
Vitest学习笔记
前端
OLong36 分钟前
第二章 - 抽象语法树(AST)概述
前端·typescript