用Compose来做两个进度动效,一个挺实用,一个挺抽象

最近杂七杂八的事情一堆,忽然发现自己好久没有写Compose了,最近的一篇Compose相关的文章离现在差不多快要两个月了,这么一想可把自己吓一跳,那么长时间了可别把Compose的东西给弄生疏了呀,尤其最近又是ArkTS又是React的,都是声明式的语法又那么接近,在不写点Compose估计就要不会写了,那么该写点啥呢?之前前前后后整了有十六个Compose的loading动效,发现做动效还挺有意思的,那么这次继续来做点动效吧,但不做loading了,做点进度动效来换换口味,打开IDE,开整~

准备工作

之前网上去搜了一下,这样的动效大多数都很千篇一律,基本都是中间一个百分比数字,周围一个圆弧,从一个小圆弧变成一个完整的圆,这样整个动效就结束了,有差异的也最多就是字体颜色,圆弧颜色,圆弧粗细之类的不一样,但是这样就很枯燥,我们这次就来做点有意思的,不一样的动效来看看,首先不管是什么样的效果,咱都需要一些数据来表示进度,这个进度就用下面这段代码来实现

一个状态变量progress,这个变量就是用来保存当前的进度,并且作为LaunchedEffect的key,首次启动,LaunchedEffect会执行它内部的协程block,block里面是一个Flow,Flow的上游判断当前progress的大小是否超过了100,超过了就重新置成0,没有超过的话就延迟200毫秒再emit个2到下游,下游拿到上游发送过来的数据之后,更新到progress上,然后重新触发LaunchedEffect执行新的协程block,就这样一个简单的改变进度的过程就做好了,后面只需要将progress传递给每个动效函数就好了,下面来做第一个动效

变大并旋转的圆弧

这个动效是之前在别的地方看到过,也是百分比跟圆弧的组合,但是圆弧除了弧度会变大之外,圆弧本身也会绕着百分比旋转,这边也来用Compose实现一下,由于要展示百分比数字,所以整个布局结构是外层一个Box,里面是一个Canvas和一个Text,Canvas用来绘制圆弧部分,Text用来显示百分比,整个结构如下

Text直接展示的就是进度的值progress,然后将RollingArc函数在外层Window函数中调用后的效果就如下所示

然后由于项目用的Compose版本是1.5.1

众所周知,Compose在1.4的版本里面已经给文本组件添加了drawStyle属性,可以轻松给文本设置上描边效果,实现起来也很容易,只要在Text组件中设置了drawStyle属性就好,样式就在里面自定义

上面这段代码就是给Text增加了一个描边效果,其中边的粗细是3f,笔触设置为StrokeCap.Square,效果就像下面这样

文本现在就呈现出只有描边,中间是空心的效果,drawStyle还可以设置其他效果,比如给文本设置虚线效果之类的,但不是本文重点就不说了,大家有兴趣可以尝试下,我们继续下一步,现在做好了百分比的跳动动画,然后就是外面的圆弧动画了,这个就要在Canvas里面使用drawArc函数来完成,我们先随便画个圆弧,比如起始角度是0度,弧度大小是90度,代码如下

这里画了一个弧度粗细是30f,位置在左上角(0,0)坐标,大小是100f * 100f的圆弧,大概的样子就像下面这样

现在要挪动这个圆弧,让圆弧的圆心刚好是整个画布的中心,那么圆弧就能绕着中间的百分比数字旋转的了,那么第一步,需要定义几个变量

代表中心点坐标的centerXcenterY,以及圆弧半径outRadius,有了这三个变量,就可以计算出当圆弧圆心在画布中心时候,topLeft的x,y坐标,代码如下

左上角x坐标就是centerX减去圆弧半径,y坐标就是centerY减去圆弧半径,而Size里面就是传入圆弧的直径,也就是两倍的outRadius,这个时候圆弧的位置就在画布中间了

接着就是动画部分,先让圆弧绕着中心旋转,这个很简单,让startAngle的值变成一个循环改变的动画变量就好

然后把start作为startAngle的值,圆弧就转起来了

圆弧转起来以后,圆弧的弧度就得跟着传进来的progress值动态改变了,直到progress值是100的时候,圆弧的弧度就变成360度,这里progresssweepAngle的转换关系是这样的

我们把这个转换关系代入到drawArcsweepAngle里面去,圆弧的弧度也就跟着progress一起改变了

这里不知道大家有没有看清,这个弧度改变的过程中有点卡顿,主要原因是我们sweepAngle的值改变的时候是从一个值直接到另一个值,没有一个过渡的过程,才会让效果看起来有点卡顿的样子,解决这个问题也很容易,我们让sweepAngle也变成一个动画变量就好,使用animateFloatAsState函数来实现

这里将progress * 3.6作为targetValue值代入到animateFloatAsState函数里面去,这样就得到了一个sweepDif的改变动画,我们将sweepDif代入到sweepAngle里去后,再来看下效果

现在sweepAngle改变的时候卡顿的感觉就不是很明显了,而这个动效也基本完成了,剩下的事情就是美化工作,让百分比字体颜色与圆弧颜色随着进度的改变有个颜色的过渡变化,要做到这一点的话首先需要一个颜色的数组

这里创建了一个颜色数组circleColorList,长度大小是11,为什么是11呢,因为我们进度progress的取值是从0-100,这些数字的十位数是0-10总共有11个,每一个十位数如果要对应一个颜色的话,那么肯定的我们这个数组长度就必须设置为11,然后再使用animateColorAsState函数创建一个颜色改变的动画

可以看到这边的targetValue取的就是circleColorList里面的值,下标是progress/10,然后再把ringColor作为我们圆弧与百分比字体的颜色,整个动效就多了一个颜色切换的效果了

这里还给颜色加了点渐变,最终整个动效就完成了

自定义进度样式

可能这里会有小伙伴吐槽,你开头不是说圆弧的动效比较枯燥,看腻了吗,怎么自己反手就做了个圆弧呢?piapia打脸了昂,好吧。。刚开始手有点生疏,所以先做个中规中矩的热热身,接下来就开始做个有意思的,这里重新再新建个函数

这里一样创建了中心点坐标centerXcenterY,可以从函数名字可以看出,这次要做的动效是要去画线,当然这线不是去调用drawLine函数去画,而是画的是贝塞尔曲线,我们都知道画贝塞尔曲线其实就是绘制Path,所以我们也要去绘制Path,绘制很多Path,所以先创建一个存放Path的数组

直接创建了一个大小是100的数组,里面也创建了100个Path,但是并没有定义具体路径,因为不同的路径所展示出来的效果也都是不一样的,比如我们这里要画的曲线是二阶的,二阶曲线的首尾控制点都在一个圆上,第一个控制点比如是在圆的0度位置,那么最后一个控制点则是在相对于第一个点再经过90度的位置,至于中间的控制点,就是在比首尾点所在的圆更大的圆上,位置就是在0和90度之间,其他曲线也都这样的逻辑,只是控制点所在的位置的角度呈递增关系,大概的绘制思路就是这样,我们现在就来将这一百个曲线绘制出来,由于有两个圆,所以再创建两个变量代表这两个圆的半径

maxRadius是比较小的圆的半径,outRadius是较大圆的半径,由于要获取圆上点的坐标,所以再创建两个函数分别去计算坐标的x,y值

两个函数所需要的参数里面,半径与中心点坐标都有了,还缺第三个参数角度,由于Path数组大小是100,所以我们将整个圆周等分为100份,每一个小圆弧跨越的角度都是3.6f,那么所有曲线的第一个控制点就有了

第二个控制点在比较大的圆上,所以半径需要使用outRadius,角度可以是在第一个点的角度基础上加上随便一个0到90度的值,比如45度,那么第二个点的代码如下

第三个控制点的半径又变成了maxRadius,角度是在第一个点的基础上加上90,所以完整的贝塞尔曲线的路径的代码如下

现在就可以在Canvas里面遍历pathList,将所有曲线绘制出来了,绘制代码如下

然后我们就能得到下面这样的图案

现在是将所有曲线都绘制出来,如果想要让绘制的曲线数量与进度progress绑定在一起,只需要在遍历时候判断一下下标index比当前progress小,满足条件的再去绘制就可以了,更改一下代码

这个时候所有曲线都可以去动态绘制了,看下效果

接下来在这个基础上再优化一下,我们给曲线设置个虚线效果,并且透明度让它随着进度慢慢增加,虚线的话可以通过设置pathEffect属性去实现,透明度直接用progress/100f,不过要判断下值,不能超出1f,不然程序就闪退了,更改后的代码如下

这个时候的效果再来看下

像不像一个钢丝球?我们给这个"钢丝球"染个色,先定义一组色值

然后在绘制Path的地方,用brush属性代替color属性将这组色值设置进去

现在的"钢丝球"就变成彩色的了

这个动效做到这里其实可以收工了,但是总感觉哪里还缺点啥?代码往上翻一翻可以发现这段代码

这是定义曲线路径的代码,其中第二个控制点的位置现在还是固定在距第一个点45度的位置,我们可以在这个值上下点功夫,比如下标为偶数的点,计算x坐标的角度为45度,计算y轴角度为55度,下标为奇数的则反过来,代码更改下就是下面这样

我们看看现在效果变成什么样子了

"钢丝球"一下子变得就有层次感了,如果想要把百分比的文本也显示出来,可以使用drawText函数,在"钢丝球"中间展示百分比文本,代码如下

具体效果就是下面这样

源码地址

总结

这篇文章里总共做了两个进度动效,一个算是比较务实,实用的,一个则比较抽象,创意元素多一些,不过目的还是为了打破那种墨守成规的思路,不一定进度动效只能设计出那种圆环,或者进度条的样式,也可以多发挥想象力,设计出更加好看,酷炫的进度效果。

相关推荐
轻口味10 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js