Compose写两个看久了会头晕的螺旋粒子动效

最近看了几篇写粒子动效的文章,发现一个现象网上写粒子动效的基本都是用web技术实现,css,canvas这些,Flutter也有一些,但是好像没有看到有人用Compose写过粒子动效(可能有,我暂时没搜到),那么今天,我们就来试一下能不能用Compose写出粒子动效

动效一:使用动画api实现

单个粒子螺旋运动

写这个动效之前我们先看下单个粒子如何做螺旋运动,比如界面上有个小圆点

让这个小圆点做螺旋运动还是很容易的,只需要一边让它做圆周运动,一边增加它圆周运动的半径就可以了,将代码改一下就是这样

使用了rememberInfiniteTransition()创建了两个循环动画变量angledis,分别代表着圆点旋转的角度以及圆点与画布中心的距离,将这两个变量带入到poXpoY函数,这两个函数是分别计算圆周上某一个点的x,y坐标

然后一个简单的螺旋动画就完成了

多个粒子的螺旋动效

我们刚才使用循环动画实现了一个粒子的螺旋运动,同样我们也可以给两个,三个,多个粒子都设置上循环动画,先创建个粒子的model

Particle代表单个粒子,里面现在有两个属性分别代表着粒子的坐标,接着我们在创建个粒子的数组,并将所有粒子都初始化出来

这里,粒子所在圆周的半径已经不用dis变量了,直接用的是当前粒子所在数组的下标值,每个粒子的角度是用当前angle减去it * 5f获得,我们再优化下angle循环动画,目标值改为360f,然后加上帧动画规格,让循环动画在每次动画结束后,角度刚好到达360度

最后一步在Canvas中遍历粒子数组plist,将所有粒子都绘制到画布上

REC_COLOR是一个颜色值的范围,在绘制粒子的时候每一个粒子的颜色都从这个范围里面随机选取,为的是让整体效果不那么单调,看下运行后的样子

现在粒子摆放的还很有规律,我们做下修改,让粒子出现的位置能够随机一点,在计算粒子坐标的时候,在粒子的半径上加上一个随机数

看到给粒子的圆周半径上增加了随机数后,整体的粒子效果就好多了,我们现在再让整体效果有点立体的感觉,Compose里面不太容易做3D效果,这里也只是按照近大远小,近淡远深的规律来做,前者就是改变粒子的大小,后者就是改变粒子的透明值,所以在Particle中再增加两个属性,粒子半径radius和透明度alpha

plist中也计算出半径与透明值

透明值的计算方式是每20个粒子就降低0.1f的透明度,半径则是每10个粒子就增加1f的半径大小,然后在Canvas的绘制过程中,将radiusalpha也添加进去,代码如下

最终我们这个螺旋粒子动效就做好了,看下效果

动效二:改变属性的方式实现

刚才我们通过使用循环动画做了一个螺旋粒子动效,这个动效里面,每一个看到的粒子的属性都是定值,不会改变,我们通过不断创建新的粒子来刷新界面来达到效果,现在我们不使用动画api,单纯的改变粒子的属性,看下能不能也做出来

思路

简单的说一下思路就是每单位时间创建一个粒子,粒子有一个初始位置,位移后的目标位置通过位移距离以及角度来计算,粒子提供一个刷新的函数,该函数内部不断增加单位时间的位移大小达到动效范围变大的目的,不断增加角度达到效果旋转的目的

创建对应属性

首先更改一下我们Particle的属性,将初始值,目标值,位移,角度等添加进去

  • startX:初始位置x坐标
  • startY:初始位置y坐标
  • endx:目标位置x坐标
  • endy:目标位置y坐标
  • dis:单位时间位移距离
  • color:粒子色值
  • angle:粒子圆周上的角度
  • radius:粒子的半径
  • alpha:粒子的透明度

生成粒子

确定好了粒子的属性后我们就要去生成粒子了,粒子生成出来后要有个数组存放,所以还得再创建个数组

生成粒子的过程在副作用函数LaunchedEffect中进行,每次生成一个,particleList的大小作为key值,这样每当有新的粒子被添加到particleList后,就会触发副作用函数再生成一个新的粒子

每个粒子的初始位置都是画布的中心点,目标位置就要通过在粒子中计算获得,所以现在我们要在粒子中增加计算目标位置的逻辑

增加了一个初始化函数和update函数,初始化函数目的是要计算出粒子刚创建出来后的目标位置,而update函数就是用来实时通过更改后的位移值与角度值更新最新的目标位置,然后我们添加下调用这个update函数的代码

很简单就一行遍历,让数组内的每个粒子都更新下目标位置,绘制粒子的地方跟第一个效果一样,就不说了,我们看下效果如何

跟刚才第一个效果一样,粒子的位置都没有错乱开来,造成这个的原因是因为我们在生成粒子的时候角度都是0度,也就是所有粒子位移角度都是从0度开始,方向都一样怎么可能会错乱乱呢?解决方法只需要在生成粒子的时候,将角度也随机就好了

看到了这里将角度变成了0到90度之间的随机角度,这里为什么不是取0到360度之间的角度呢?别忘了我们是要做螺旋动效,如果初始角度范围太大的话,就没有螺旋的效果了,我们看下加了随机角度后的效果

有点样子出来了,现在就是粒子有点太小了,所以接下来我们要增加粒子的半径大小,这个就简单多了,只需要在update函数中逐渐增加radius的值就好了

看看加了一行代码后的区别

给粒子加上大小的变化之后,整体的立体感就出来了,现在除了大小,我们再给粒子添加上透明度的变化,让透明度不断减少直到为0,在update函数中加上alpha值的变化

加上透明度的变化后效果会变成啥样呢?一起来看下

由于加了透明值的变化,螺旋上的粒子会旋转一定弧度之后消失,加强了整体的立体感,但是虽说现在这个动效差不多已经完成了,但是感觉哪里还缺点啥,我们发现整个螺旋动效里面几乎所有位置的粒子都在动,只有一处不太合群没有动,就是这

虽说那里是创建粒子的地方,但也可以边动边创建啊,所以我们接下来也让那个地方转起来,咋转呢?其实就是将startXstartY也放在一个圆周上旋转就好了,这个圆周的半径就没必要一直增加了,可以按照喜好自己定义一个,然后每次在副作用函数中生成粒子前,角度增加一点,在利用poXpoY计算出对应坐标就好,代码如下

新增一个innerAngle用来记录旋转的角度,圆周的半径定为30f,这样通过poXpoY就能把初始位置的圆周坐标给计算出来了,所有代码都写完了,上一个最后的效果图

总结

这次做的两个粒子动效,一个用了Compose的动画api,一个单纯的靠刷新属性,结果都可以完成螺旋粒子的效果,其实粒子动效有很多种,除了其他博主已经实现过的,还可以发挥想象力做出一些别的效果出来,最近我也一直在思考能不能用Compose去实现不同效果的粒子动效,有点魔怔了,不说了,下篇文章见,886~

相关推荐
秦jh_10 分钟前
【Linux】多线程(概念,控制)
linux·运维·前端
帅次13 分钟前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
蜗牛快跑21322 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy23 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与2 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun2 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇2 小时前
ES6进阶知识一
前端·ecmascript·es6