用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函数,在"钢丝球"中间展示百分比文本,代码如下

具体效果就是下面这样

源码地址

总结

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

相关推荐
YB13752 小时前
Kotlin 三类关键字
kotlin
mldong6 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排7 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60617 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角8 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰9 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
撩得Android一次心动10 小时前
Jetpack Compose 知识点整理1【个人用】
android·学习·kotlin·android jetpack·compose
mayaairi10 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen11 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能