说到进度动画,很多人脑海中肯定会出现类似于一个长条的进度条,或者是一个圆环进度条,这种样式是目前比较常见的,但今天要实现的进度动效它并不像那种常见的进度条,而是只有一个百分比数字,数字周围会带有不断更换颜色的霓虹灯特效,而数字本身也使用的是像素字体的样式,接下来就看看这种动效是如何实现的
注:本篇文章进度的数据来源是与上一篇文章公用的同一段代码,如果想知道进度本身是如何实现的,可以去上一篇文章里面查看
在指定范围内绘制像素点
要实现霓虹灯效果的话,第一步就是将我们的画布等分成若干个小格子,然后在每个小格子的交叉点位置绘制小圆点作为像素点,下面是绘制像素点所需要的变量
- screenW:画布的长度
- screenY:画布的宽度
- gridCount:水平或垂直方向上等分的数量
- xUnit:水平方向每一小格的宽度
- yUnit:垂直方向上每一小格的高度
- pRadius:像素点的半径
- xList:存放所有像素点的x坐标
- yList:存放所有像素点的y坐标
在Canvas
里面,通过遍历xList
与yList
,可以将所有像素点都先画出来
最后得到的如下这个效果
不能看太久,看久了眼花,这么个眼花的东西我们是在循环体内没有加任何判断画出来的,那么如果我只想在某一个具体范围内绘制出所有的圆点该怎么做呢?比如在一个半径为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
组件,Surface
的shape
属性还设置了CircleShape
,为的是与霓虹灯发光的范围形成统一,接下来就是重点,如何去实现像LED一样像素样式的字体,上面有说过LED是用发光的格子拼在一起,那在我们这里就是将若干个具体位置的格子设置上颜色,注意这里用到了具体两个字,也就是说必须明确知道点亮某一个数字用到的所有格子的具体坐标,那么一个严肃的问题就来了,好家伙我们这里可是有一百个数字,外加一个百分号,整体都要在我们的LED布局里面居中显示,也就是说就算是同一个数字,在不同的百分比里面所使用的坐标点都是不一样的,那我是不是要把一百个百分比数字的坐标都算出来?当然不是,思路来自于下面这张图
这是啥大家都认识,计分牌,我网上随便找的,计分牌如何来表示一个比分的大家都清楚,将两个数字组合在一起就好了,那么我们的思路不就打开了吗,在一个LED布局里面显示一百个百分比数字是比较复杂,那么我们如果将LED布局拆分开来,让每一个子LED布局只负责显示单个数字或者百分号,因为在单个LED布局里面,每一个数字或者百分号的坐标都是固定的,最终一个完整的百分比数字就是由若干个子LED布局拼凑起来形成,那不就完事了吗?好了,说了那么多咱思路也理清了,现在可以动手开发,首先创建一个新的函数来表示单个子LED布局
由于同样是要从画网格开始的,所以所用到的变量与绘制霓虹灯用到的基本一致,差别在于gridCount
变小了,变成了一个8 * 8的小网格,而在入参方面,除了必要的Modifier
,还多了两个参数,一个是传进来需要变成像素字体的value
,另一个则是像素字体的字体颜色,这里同样先把所有小格子绘制出来
然后在上面的Surface
里面调用一下LedChild
函数,就获得了64个小方格
这里发现整个方格布局没在Surface
组件的中间位置,其实这是正常现象,因为绘制单个小格子的时候,每个格子的左上角坐标才是xList
与yList
里面的值,所以导致的结果才是整体看起来不是很居中,这些可以忽略的,有了这些方格之后,每个数字就是由这些方格里面的其中几个组合起来的,每个数字或者百分号都有自己对应的方格集合,这里创建一个GridPoint
类表示单个方格,里面维护着这个方格的左上角x,y坐标
在LedChild
函数里面创建个Map
,这个Map
的key
就是单个数字或者百分号,value
就是一个GridPoint
数组,比如说数字1,它的GridPoint
数组就是这样的
Canvas
里面的绘制逻辑也要更改下,变成只遍历value
对应的数组,将数组里面对应的方格绘制出来
咱现在实验一下,在刚才调用LedChild
函数的地方,将第二个参数从空字符串变成1,那么一个像素字体的数字1就出现了
其他数字以及百分号都一样,都是通过数对应的格子算坐标,由于行数比较多也没啥技术含量,这些代码就不贴了,有兴趣的可以把源码下下来看看,到了这里我们的LedChild
函数的开发就都结束了,一个LedChild
函数相当于一块小的LED牌子,当我们收到progress
时候,需要将progress
拆分成若干个个位数,外加一个百分号,每一个部分都分别对应一个LedChild
,在Surface
里面加上这样的逻辑,代码如下
这样一个用像素字体实现的百分比进度动效就完成了,看下效果
是不是有那感觉了,再稍微美化一些,现在字体都是白色的,我们让它跟周围霓虹灯使用一样的色值,也就是将lightColor
传给每一个LedChild
函数
这样我们这个带有霓虹灯特效的进度动效就完成了,来看看最终效果
总结
本篇文章的动效制作全过程都已经介绍完毕了,希望大家能够喜欢,有任何建议或者看法观点的,也欢迎在评论区留言。