注册

天气太热,希望这个小风扇能给你带来一点凉意

最近气温多变,这几天又回到了三十多度的高温天气,在这样的天气里面如果办公室里面不开个空调或者电风扇的话,那么是很难集中精神工作的,空调的话可能每个办公室都有,但风扇的话估计要自己去准备了,如果还没来得及准备的话,那么可以先考虑下在桌面上画个风扇看着它吹,毕竟古人有望梅止渴,我们今天就来画风扇降温


源码地址


github.com/coffeetang/…


准备工作


首先考虑下这个风扇的结构,我们这个风扇总共有这几个部分组成,分别是底座,立柱,扇框,扇叶,底座上有总开关,有可以调节风速强度的开关,那么整体来看是个上下结构,底座在最下面,其他的在上面,除了底座其余的都绘制在一个Canvas里面,大致结构如下


image.png

扇叶


风扇的扇叶,其实可以看成是在画布上画扇形,而我们画扇形就要用到函数drawArc,这个函数的传参列表如下所示


image.png

参数我们都很熟悉了,这里绘制扇形所需要用到的参数有



  • brush:用来设置渐变色的
  • startAngle:表示起始角度
  • sweepAngle:表示扇形角度
  • userCenter:表示扇形两端是否与圆心相连
  • topLeft:表示绘制扇形范围的左上角坐标
  • size:表示扇形的绘制范围
  • style:默认值就是Fill填充的,所以我们可以不用去挂心

根据参数,我们需要创建几个变量,首先是圆心坐标,它是取的Canvas的中心坐标,所以无论窗口变大变小,我们的圆心坐标都会在整个画布的中心位置


image.png

其次是我们的半径,半径的大小决定了整个扇形绘制的范围大小


image.png

那么我们绘制一个扇形的代码就是下面这样的


image.png
image.png

一个扇形就这样画出来了,而一个风扇总共有三个扇叶,咱要画三个扇形,而且是圆周上等分的,该怎么画呢?这里使用这个方法,首先创建一个数组,这个数组里面是每个扇形要用到的渐变颜色


image.png

然后再创建一个数组,这个数组里面是每个扇形的startAngle


image.png

那么首先我们就可以通过遍历数组的方式,把六个扇形都画出来


image.png
image.png

我们看到这个时候界面上展示的就是一个由六个扇形组成的大圆形,然后我们把colorList里面每隔一组颜色就把颜色改成透明的,那么这个圆形就看起来就像是三个被等分的出来的扇形一样了


image.png
image.png

扇框与立柱


扇叶已经完成了,接下来就是绘制扇框与立柱的工作,这两个都比较容易,立柱就是从圆心位置向下绘制出一条直线


image.png
image.png

然后我们在扇形靠外一点的位置绘制一个圆形作为扇框的边框,这里用到了drawPath函数,drawPath的第一个参数是Path,所以我们先将Path做出来


image.png

然后再调用drawPath函数,将framePath传进去


image.png
image.png

然后就是风扇前面的网罩,网罩常见的有从中心向外延伸出去的一条条直线,也有的就是一个个井字格组成起来的样子,这边按照前者做个网罩样式出来,这种样式与扇叶的思想有点接近,都是按照角度在一个圆周上等分的绘制样式,所以我们首先需要确定好这些角度,也有一个list维护起来


image.png

这里就是有45根线,每过8度画一根,而我们知道绘制线条用到的函数drawLine需要知道一个start坐标和一个end坐标,start都知道是圆形坐标,而end的xy坐标就要根据角度与半径算出来了,计算的代码如下所示


image.png

第一个参数就是网罩的半径长度,第二个参数为圆形x坐标或者y坐标,第三个参数是角度,那么我们就可以使用这两个函数,遍历lineAngleList来绘制出网罩


image.png
image.png

绘制风扇部分就完成了,下面开始开发底座上的开关


总开关与强度开关


底座上的开关分两个区域,左边是调节强度的区域,右边是总开关区域,总开关设计成一个滑块的样式,滑块默认在左边为关闭状态,点击或者拖动滑块,滑块滑动到右边,状态变成开启,滑块高亮,首先建立一个变量用来记录当前开关状态,再定义两个常量分别代表关闭与打开


image.png

默认为关闭状态,滑块的实现我们需要用到swipeable操作符,参数列表如下


image.png

其中我们需要用到的参数有



  • state:滑块的状态,需要监听滑块的状态来更新开关的状态值
  • anchors:锚点,某个位置对应滑块的一个状态值
  • thresholds:阈值,判读一个鼠标拖动事件滑动到某个位置的时候,这个位置属于哪种状态,那么当鼠标停止拖动时候,滑动可以animate到对应状态位置
  • orientation:拖动方向

根据需要的参数我们来创建对应的变量,滑块的代码如下所示


image.png
image.png

这里滑块的背景颜色会根据开关状态来变化,而开关的状态我们就通过监听swipeState来更新


image.png
0606aa1.gif

我们拖动滑块改变开关状态的功能如上图所示完成了,而点击滑块边上区域来改变开关状态就需要在滑块父布局上添加点击事件,点击一次更新滑块状态,而更新操作需要用到SwipeableState里面的animateTo函数,这个函数是个挂起函数,所以还需要给它提供一个协程作用域,恰好我们更新滑块状态是根据点击来触发的,所以这里选择使用LaunchedEffect函数


image.png
0606aa2.gif

滑块部分就做完了,然后是左边区域的调节强度功能,这个区域准备由三个色块组成,每个色块都可以点击,每点击一个色块,强度设置成对应级别,符合该级别的色块颜色高亮,否则就变暗,所以这里也需要一个表示强度的变量值


image.png

然后添加上三个色块以及每个色块的逻辑代码和点击事件


image.png
0606aa3.gif

这里每个色块高亮的条件都不一样,但是有个共同条件就是必须是开关状态开启的情况下才能高亮,如果关闭的话,所有色块都会变暗,另外fanState对应的值有1000,600,200的原因我们接下去会说,这个跟风扇的转速有关


让风扇转起来


让风扇转起来从代码的角度就是让扇形每次绘制的位置不同就可以了,而从我们绘制扇形的函数drawArc里面的参数来看,要更改扇形绘制的位置那就是改变startAngle的值,也就是它的初始值加上一个时刻改变的值,这个改变的范围就是0f~360f,那么对于这个循环变化的过程,我们肯定第一个想到的就是使用循环动画


image.png

这边我们看到了,fanState的值其实就是循环动画的时间,fanState的值越小说明转速越快,另外动画的初始值与目标值也加上了fanState的值,这样做的目的是为了当fanState变化时候,需要让Composable函数animateFloat触发重组,这样才能重新生成新的InfiniteRepeatableSpec对象,改变转速,不然的话,animateFloat的三个参数都不发生变化也就不发生重组,wheelState依然还是最初的值,wheelState的值拿到以后,就可以把它加给drawArc函数里面的startAngle


image.png

这里还加了一个判断,当开关是开启状态下,drawArcstartAngle才加上变化值wheelState,当关闭状态下,则不加这个值,也就是风扇处于静止状态,我们再来看看效果


0606aa5.gif

总结


我们这个风扇也做完了,用到的知识点都是平时Compose开发中常用,像是循环动画,Canvas绘制以及手势操作之类的,就这样简简单单在电脑屏幕上画出来了一个风扇,不知道看完这篇文章的你能否感受到一丝凉风~


作者:Coffeeee
链接:https://juejin.cn/post/7244337505494401085
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册