用Compose实现一个像素字体加霓虹灯效果的进度动效

说到进度动画,很多人脑海中肯定会出现类似于一个长条的进度条,或者是一个圆环进度条,这种样式是目前比较常见的,但今天要实现的进度动效它并不像那种常见的进度条,而是只有一个百分比数字,数字周围会带有不断更换颜色的霓虹灯特效,而数字本身也使用的是像素字体的样式,接下来就看看这种动效是如何实现的

源码地址

注:本篇文章进度的数据来源是与上一篇文章公用的同一段代码,如果想知道进度本身是如何实现的,可以去上一篇文章里面查看

在指定范围内绘制像素点

要实现霓虹灯效果的话,第一步就是将我们的画布等分成若干个小格子,然后在每个小格子的交叉点位置绘制小圆点作为像素点,下面是绘制像素点所需要的变量

  • screenW:画布的长度
  • screenY:画布的宽度
  • gridCount:水平或垂直方向上等分的数量
  • xUnit:水平方向每一小格的宽度
  • yUnit:垂直方向上每一小格的高度
  • pRadius:像素点的半径
  • xList:存放所有像素点的x坐标
  • yList:存放所有像素点的y坐标

Canvas里面,通过遍历xListyList,可以将所有像素点都先画出来

最后得到的如下这个效果

不能看太久,看久了眼花,这么个眼花的东西我们是在循环体内没有加任何判断画出来的,那么如果我只想在某一个具体范围内绘制出所有的圆点该怎么做呢?比如在一个半径为40f的圆内绘制点,其他地方不绘制,这里就要将代码改一下

这边先计算两点之间的距离,使用了勾股定理,把画布中心点的x坐标与其他点的x坐标的差值的平方,加上画布中心y坐标与其他点y坐标的差值的平方,最后在用sqrt函数开根号,得到的值如果是小于40f的才去绘制圆点,比40f大的就不绘制,那么得到的效果是这样的。

我们得到的就不是满满一窗口的白点了,而是一小坨白点,这部分白点离开画布中心距离都是小于40f的,到了这里我们就已经能控制绘制像素点的范围了,来进行下一步

改变像素点的半径与透明度

下一步就是去改变像素点的半径与透明度,肯定不是去设置某一个固定的值,而是要按照一种比例去改变,什么比例呢?刚刚我们已经尝试了在一个40f为半径的圆内绘制小圆点,这个时候的小圆点的半径是一倍的pRadius并且完全不透明,那么现在想要再往外40f的范围,透明度跟半径都降低十分之一,再往外相同的距离,透明度跟半径都再降低十分之一,来看下代码

可以看到这里将单个范围大小的值提出来作为了一个变量circleSize,然后将所有的点与画布中心距离radius除上circleSize,除出来得到的值如果不超过9就去绘制点,这就相当于把整个绘制范围分成了十份,每一份的透明度与半径缩小的比例在用下面if语句里面的第一行代码计算出来了,radio就是缩小比例,然后在drawCircle里面将半径乘上radio,并且把radio直接作为透明度,我们想要的效果就出来了

效果是有了,但需要修改一下,因为要做的霓虹灯效果是从中间开始向外扩散的,而现在我们做出来的效果是向内聚拢的,所以要将代码改一下

这里稍作修改,将半径乘上的比例以及透明度从radio变成1-radio,并且把半径增大一倍,为的就是去掉圆点之间的空隙,现在感觉应该差不多了

看起来中间的好点了,但是比较靠外的范围内的圆点之间还是有点缝隙,那我们再把半径增大一点吗?当然不是,真这么做的话效果上就会打折扣了,我们可以给画布添加上一点模糊设置,使用blur函数实现

blur函数里面radius设置了3.dp,这个radius设置的越大,模糊的就越明显,这里设置个3.dp就可以了,再来看下效果

现在是不是就像一个白色的光源在发光一样了,离最终霓虹灯效果越来越近了,还差一步美化工作。

霓虹灯效果

现在这个光的颜色目前还是固定设置成了白色,我们可以根据传进来的progress参数,让发光的颜色跟随着进度来改变,先创建个颜色的数组用来切换

这里打算传进来的进度每经过10个数字,颜色就变换一下,再加上最后进度到了100的时候也要有一个对应的颜色显示,所以我们这个颜色数组lightColorList大小是11,而当前展示的颜色就是lightColorList[progress/10],我们可以直接通过访问数组下标的形式设置当前发光的颜色,就像这样

但是这么做的话颜色切换时候效果就会显的比较生硬,最好的做法是切换的时候有个动画过渡的过程,所以这里需要使用animateColorAsState函数生成一个动画变量lightColor,把lightColor设置到drawCircle函数里面去

增加了颜色切换的效果之后,整个发光效果就变得不那么单调了,现在再给这个发光的效果增加一个闪烁的动画,怎么闪烁呢?大家应该还记得我们整个发光的范围是根据点到画布中心的距离radius除上单个扩散距离circleSize来决定的,circleSize越大,整个发光范围就越大,circleSize越小,发光范围就越小,比如我们将现在circleSize从40f调到30f后,效果就变这样了

发光范围就变小了点了,按照这个如果我们不断来回更改circleSize的大小,那么是不是就有了闪烁的效果了呢?,方式就是将circleSize从一个固定的值变成一个循环改变的值,代码如下

创建了一个循环动画,将circleSize变成了一个循环改变的值,闪烁的效果就做好了,最终霓虹灯的特效也出来了

像素字体展示百分比

做完了霓虹灯效果,就得在这个霓虹灯上展示百分比进度了,其实简简单单放一个Text组件或者使用drawText来显示百分比也是可以的,而这里使用像素字体的灵感是主要来自于路边那些店铺商家门口的LED广告牌,那些LED牌子上展示的内容就是通过一个个发光的小格子拼起来组成的,那我这边也有小格子,不是也能实现下这样的效果吗,那就也来试试看,首先由于现在的画布已经用来绘制霓虹灯效果了,所以这个像素百分比需要展示在一个新的布局上面,两个视图要叠在一起,所以外面还得在加一层Box组件,修改下原来的布局结构,就是下面这样

LED布局的父组件使用了Surface组件,Surfaceshape属性还设置了CircleShape,为的是与霓虹灯发光的范围形成统一,接下来就是重点,如何去实现像LED一样像素样式的字体,上面有说过LED是用发光的格子拼在一起,那在我们这里就是将若干个具体位置的格子设置上颜色,注意这里用到了具体两个字,也就是说必须明确知道点亮某一个数字用到的所有格子的具体坐标,那么一个严肃的问题就来了,好家伙我们这里可是有一百个数字,外加一个百分号,整体都要在我们的LED布局里面居中显示,也就是说就算是同一个数字,在不同的百分比里面所使用的坐标点都是不一样的,那我是不是要把一百个百分比数字的坐标都算出来?当然不是,思路来自于下面这张图

这是啥大家都认识,计分牌,我网上随便找的,计分牌如何来表示一个比分的大家都清楚,将两个数字组合在一起就好了,那么我们的思路不就打开了吗,在一个LED布局里面显示一百个百分比数字是比较复杂,那么我们如果将LED布局拆分开来,让每一个子LED布局只负责显示单个数字或者百分号,因为在单个LED布局里面,每一个数字或者百分号的坐标都是固定的,最终一个完整的百分比数字就是由若干个子LED布局拼凑起来形成,那不就完事了吗?好了,说了那么多咱思路也理清了,现在可以动手开发,首先创建一个新的函数来表示单个子LED布局

由于同样是要从画网格开始的,所以所用到的变量与绘制霓虹灯用到的基本一致,差别在于gridCount变小了,变成了一个8 * 8的小网格,而在入参方面,除了必要的Modifier,还多了两个参数,一个是传进来需要变成像素字体的value,另一个则是像素字体的字体颜色,这里同样先把所有小格子绘制出来

然后在上面的Surface里面调用一下LedChild函数,就获得了64个小方格

这里发现整个方格布局没在Surface组件的中间位置,其实这是正常现象,因为绘制单个小格子的时候,每个格子的左上角坐标才是xListyList里面的值,所以导致的结果才是整体看起来不是很居中,这些可以忽略的,有了这些方格之后,每个数字就是由这些方格里面的其中几个组合起来的,每个数字或者百分号都有自己对应的方格集合,这里创建一个GridPoint类表示单个方格,里面维护着这个方格的左上角x,y坐标

LedChild函数里面创建个Map,这个Mapkey就是单个数字或者百分号,value就是一个GridPoint数组,比如说数字1,它的GridPoint数组就是这样的

Canvas里面的绘制逻辑也要更改下,变成只遍历value对应的数组,将数组里面对应的方格绘制出来

咱现在实验一下,在刚才调用LedChild函数的地方,将第二个参数从空字符串变成1,那么一个像素字体的数字1就出现了

其他数字以及百分号都一样,都是通过数对应的格子算坐标,由于行数比较多也没啥技术含量,这些代码就不贴了,有兴趣的可以把源码下下来看看,到了这里我们的LedChild函数的开发就都结束了,一个LedChild函数相当于一块小的LED牌子,当我们收到progress时候,需要将progress拆分成若干个个位数,外加一个百分号,每一个部分都分别对应一个LedChild,在Surface里面加上这样的逻辑,代码如下

这样一个用像素字体实现的百分比进度动效就完成了,看下效果

是不是有那感觉了,再稍微美化一些,现在字体都是白色的,我们让它跟周围霓虹灯使用一样的色值,也就是将lightColor传给每一个LedChild函数

这样我们这个带有霓虹灯特效的进度动效就完成了,来看看最终效果

总结

本篇文章的动效制作全过程都已经介绍完毕了,希望大家能够喜欢,有任何建议或者看法观点的,也欢迎在评论区留言。

相关推荐
Qrun7 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp7 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.8 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl10 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫11 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友11 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理13 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻13 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front14 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰14 小时前
纯flex布局来写瀑布流
前端·javascript·css