用Compose在桌面上做个带粒子动画和像素字体的数字时钟

展示时间的方式一般要么是用钟表形式,要么是用数字形式,我在之前的文章中已经用过Compose实现了一个钟表的时钟,但是数字时钟还没有做过,主要是实现个数字时钟太容易,调用个时间api获取当前时间然后渲染到一个文本组件上,功能就完成了,没啥好做的,但如果在这简易的功能上做一些扩展,比如在切换时间的时候加个粒子动效的过度,比如使用像素字体来展现数字,比如让它能常驻在桌面上充当一个真正的时钟角色,那么这个数字时钟就看起来不那么单调了,下面就开始来看看如何实现这个时钟

粒子动效

整个过程比较关键的就是实现粒子动效,由于水平有限没法将这个效果做的太酷炫,只能先实现个简易版的,也就是随机在一个范围内绘制若干个粒子,首先创建个函数ParticleClock,在内部添加一个Canvas以及获取这个Canvas的大小

当画布创建出来后,就可以通过mSize来获取画布的宽高,接着再创建个变量count来表示单次绘制的粒子数量,然后创建个pointList用来保存单次需要绘制的所有粒子

SingleParticle封装着每一个粒子的xy坐标

生成一组粒子的操作也就是循环count次,每一次新建个SingleParticle,里面的xy坐标取宽高的随机值,代码如下

创建好了粒子之后,就要开始绘制了,由于我们的数字时钟采用像素字体,而每一个像素其实就是一个小的矩形,所以我们的粒子也用矩形来绘制,这样当粒子动效结束过度到数字时钟的时候就不会显的很违和,绘制代码如下

现在界面上就有五十个随机绘制的小矩形

这里稍作优化,现在每个粒子的宽高都是固定的大小,但是我们希望粒子的大小可以随着窗口的变化,粒子数量的变化而改变,所以这里需要将每个矩形的宽高更改为mSize.width/countmSize.height/count,更改后的代码以及效果图如下

现在绘制的粒子都是静态的,如果想让粒子可以动态绘制的话,就必须通过重组每次新建一个pointList并塞入新的一组粒子,这样每次绘制粒子的位置就都不一样了,为此这里需要创建一个状态变量index,然后每单位时间更改一下这个值

这里使用LaunchedEffect定时更改index值,这样index更新后,pointList内部的粒子也刷新了,我们看一下效果

更改粒子的绘制高度

大概的一个粒子动效就有了,现在需要再粒子动画的过程中逐渐改变粒子的绘制高度,直到高度的变化值达到一个定值的时候再将时钟展示出来,这个变化值就由index记录着,而定值就设置为mSize.height/3,这样当上下高度都缩小mSize.height/3后,中间剩余的mSize.height/3高度就可以用来展示时间,我们在LaunchedEffect里面更改一下代码

这里当index的值到达mSize.height/3之后,将index的值重置为0,这样变小的绘制范围又重新恢复到原样,此外由于这边的粒子绘制高度发生了变化,在给pointList赋值的时候,每一个SingleParticle的y值的取值范围也要对应的改变,代码如下

这里除了rangeY的取值范围与index绑定在了一起之外,rangeX的取值也变成了50与mSize.width.toInt() - 50之间,让粒子的绘制范围与两边留有一些空隙,那么现在粒子的绘制范围可以跟着index的变化而改变了,效果如下

显示时间

粒子的动效做的差不多了,现在要开始将时钟展现出来,要达到的效果就是当index值达到mSize.height/3的时候,隐藏粒子,展示时钟,那么这里需要一个状态值来控制这两个视图的隐藏展示

index值达到mSize.height/3的时候showNumber设置为true,并且延迟个一段时间再将showNumber变成false,那么这个延迟的时间就是时钟的展示时间,一样在LaunchedEffect中加入这些逻辑

那么现在就开始时钟的绘制,由于我们的时钟的文字使用的是像素字体,这个在之前的一篇文章中有讲过如何制作像素字体的数字,所以这里直接将那边的代码拷了一份过来,在创建像素字体的函数中添加对时间中间的冒号符号的支持

再创建一个函数ClockItem用做创建时钟上的时分秒,也就是判断下传进来的数字的位数,然后决定使用一个DigitalNumber或者是两个DigitalNumber来展示

最后在创建个表示时钟的函数ClockDigital,除了接受些必要的参数如Modifier之外,还接收当前时间对象LocalTime.now(),内部分别时候三个ClockItem代表时分秒,两个DigitalNumber表示冒号

时钟部分的代码就是这些,我们将函数ClockDigital与绘制粒子的Canvas都包在一个Box组件内部,用变量showNumber来控制展示哪个组件

整体的一个逻辑代码就完成了,来看看效果如何

可以很容易的发现个bug,也就是同一个时间它出现了两次,造成这个bug的原因主要是因为没有将粒子的动画时间控制好,理论上来说由于时间的展示时间为500毫秒,那么粒子的动画时间也应该是500毫秒,然后这个500毫秒也包含了创建数据以及渲染数据的时间,所以index从0变成大于mSize.height/3要比500毫秒小,经过调试最终index每十毫秒的增值如下所示

看下效果

窗口透明

最后一步了,现在整个数字时钟也完成了,我们需要让它摆放在桌面上某一个位置让它在那边静静地跳,要做的就是去掉边框,让窗口透明,代码如下

transparentundecorated属性是让窗口透明,alwaysOnTop是可选项,目的是让窗口永远浮在其他窗口上面,一直可见,在运行一下项目,在桌面的底部就出现了我们的数字时钟了

总结

一个带粒子动画和像素字体的数字时钟完成了,多多少少以后这个也能在桌面上当作一个时钟工具了,或者到了中午将它整成全屏直接作为一个屏保,让它在那边跳,然后你去吃饭也是可以的,这个大家有兴趣的可以自己拿去调一下样式,比如外围加个边框,或者多一些颜色搭配,这个就看个人喜好了~

相关推荐
DK七七19 分钟前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客30 分钟前
QSS 设置bug
前端·bug·音视频
Chikaoya31 分钟前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季31 分钟前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie31 分钟前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
NoloveisGod1 小时前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing1 小时前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚1 小时前
实现3D热力图
前端·javascript·3d
杨过姑父1 小时前
org.springframework.context.support.ApplicationListenerDetector 详细介绍
java·前端·spring
理想不理想v2 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试