距离上次做飘动的小球的屏保现已过去了一个多月,发现那些小球看多了也腻,可是想再做个屏保么也没啥思路,可是前阵子在陪娃看了个新出的动画片,叫啥量子战队的,里边主角总部的墙引起了我的留意,那是一个个小格子,每个格子是六边形形状,就像蜂窝相同,然后全体色彩还会慢慢改动,这一下子灵感就挠得一下就上来了,我也来撸个蜂窝墙出来
源码地址
规划思路
全体的一个规划进程分以下几步
- 整个进程分为翻开屏保与封闭屏保
- 翻开屏保的时分,首先展示一个蜂窝墙的一个架子
- 架子展示完之后,逐步给一个个蜂窝格子填充色彩
- 填充完色彩之后,整个蜂窝墙布景出现一个多色突变而且布景顺时针旋转
- 封闭屏保时,上述进程反向操作,终究退出程序
第一步:先做屏保开关
在Window
函数中创立一个MenuBar
,而且里边有两个Item
,别离用来履行翻开与封闭屏保的操作,咱们在创立一个switch
变量,并让它作为参数传入屏保的Compose函数中,点击Item
的时分,改动switch
的值,代码如下
第二步:蜂窝墙架子
一个蜂窝墙架子,其实便是一个六边形的网格布局,平时让咱们画一个圆点布局,会画,画一个正方形格子布局,也能画,可是六边形布局咋画呢,DrawScope
里翻了一圈也没找到对应的Api,那么只能“徒手画”了,先剖析下六边形网格布局的特点,它看起来是由若干个点朝着圆周上三个方向延伸出去三根直线,当每一个点的三根直线与其他点的三根直线重合的时分,一个六边形网格布局就形成了,咱们只需要将这些点找出来,然后在根据视点计算出延伸方向的终点坐标,将两点连起来就好了,听起来像是这么一回事,可是先看看下面的图
咱们看到中间的横线左右两个端点延伸出去的直线,视点是不相同的,也便是说咱们不只要找出一切的点,还必须确认好每一个点延伸出去的方向才能制作不同的直线,那这个工作量无疑是庞大的,咱们得找找其他方案,得找出一个固定不变的制作规则,有吗?咱们再看看下面这张图
这是一个六边形网格布局的一部分,咱们看中间那个六边形,这个六边形的中心点咱们用黑色标出来了,咱们发现这个黑点到六边形六个角的视点别离为0,60,120,180,240,300,而且每一个六边形都有这样的规则,那么咱们是不是能够找出一切六边形的中心点坐标,然后计算出六个角的点坐标,而且将相邻的视点计算出来的坐标连起来,六边形布局就完成了呢,那么先创立出一个寄存视点的数组,以及六边形的边长
anglist
便是寄存视点的数组,而radius
便是六边形的边长,同时也是中心点到每一个角的距离,接下来便是思考下怎么将一切的中心点找出来,咱们再看看下图
请无视我粗糙的画功,咱们将之前那张图补充点元素便是上面这个图,其间第一排与第三排的中心点,它们第一个点都与画布边距一个radius
的距离,紧接着便是3 * radius
的距离递增,而第二排与第四排的中心点略有不同,第一个点没画出来,它在画布外面,与画布边距是负的0.5 * radius
的距离,然后也是3 * radius
的距离递增,经过这些能够将中心点的横坐标确认下来
xUnit
为中心点之间横坐标的距离,xLength
是单排横向上的格子数量,加一是为了防止边上出现不完好的格子,xList
与xList2
是单排与双排的横坐标数组,咱们再来看看上图来确认纵坐标,两个中心点的纵向距离为两倍的中心点到六边形底部的距离,那这个距离怎么算呢,咱们运用勾股定理就能算出来,radius
的平方减去一半radius
的平方开根号就得到了,代码如下
yUnit
便是咱们刚刚运用勾股定理算出来的两点纵向距离,yLength
同xLength
相同,加上一防止有不完好的格子出现,yList
与yList2
是单列与双列的纵坐标数组,现在就能够经过遍历单排单列坐标与双排双列坐标将一切六边形画出来了
其间pointX
与pointY
函数是用来经过半径,中心点与视点计算出终点横纵坐标,代码如下
运转一遍程序之后,就获得了咱们蜂窝墙的一个架子了
现在咱们结合之前做好的开关,让这个架子能够在翻开开关之后才出来,那么未翻开的时分网格便是通明色的,翻开才是白色,所以这儿有个色彩的过渡进程,咱们运用animateColorAsState
函数来完成
这儿新建了一个Int
的变量gridSwitch
来作为咱们动画的真实开关,当不为0的时分,格子色彩永远是白色,这样做的目的是为了当咱们封闭屏保的时分,假如直接运用布尔变量switch
,那么就会直接让格子消失,就不会有规划思路里边说的将翻开动画反向再履行一遍的进程,现在咱们将gridColor
代入到drawLine
的函数里边,就初步得到一个翻开网格的进程
现在在网格出现的时分增加一个作用,现在咱们看到的是整个网格都展示出来,现在只让网格的穿插点先出来,等穿插点出来之后,两点之间再延伸出一根白线将点连在一起,怎么做呢?是动态改动drawLine
的start
点或者end
点吗?不是的,咱们这儿运用PathEffect
里边的dashPathEffect
函数,这个函数看名字就知道是用来画虚线的,怎么画呢,看下它源码里边咋说的
一大堆注释,概括一下便是这个函数需要传入两个参数,第一个参数intervals
是一个float
数组,一般这个数组里边放两个值,第一个是实线长度,第二个是实线间的距离大小,第二个参数phase
,感觉这个命名改成offset
更适宜,意思便是制作线的起始位置朝反方向挪动phase
距离,默许是0,那么我先用PathEffect
给网格的线加个虚线作用试试
这儿给虚线作用设置的是实线长为10,距离长也为10,原因是咱们单条线的radius
之前是现已设置好了30,所以距离与实线长度联系是实线长度=(radius-距离长)/2,当距离长刚好等于radius
的时分,那么只剩穿插点,没有线了,反之当距离为0的时分,那么距离就看不到了,经过这两个临界值以及实线与距离的联系,咱们能够做出一个点与点相连变成网格的动效
咱们给虚线的动效新建个开关dashState
,而且在gridColor
动画完毕之后,将dashState
开关翻开敞开连接动画,另外将dash
代入到制作drawLine
函数中
第三步:给蜂窝填充色彩
这儿的填充色彩不是简略的将整个画布设置个色彩就完事了,而是需要在每一个格子都设置个色彩进去,那么问题来了,咱们之前画格子是只画了线,格子内部其实是啥也没有的,所以与其说是填充色彩,还不如说是画一个带色彩的六边形,还是逃不了啊,那就只能画了,之前说drawScope
里边没有现成的api来画六边形,那么咱们能够多走一步,经过制作Path
来形成六边形,道理也是相同的,先是moveTo
到一个点,然后drawLine
到下一个点,一圈下来也是个六边形了,那么第一步,需要收集好一切六边形的中心点,这样才能达到能够在随意一个位置就画六边形的作用
这儿的pointList
便是拿来放一切中心点的数组,pathList
用来寄存终究制作六边形Path
的数组,然后咱们在制作六边形格子的时分,顺便将每个中心点add
到这个pointList
里边去,像这样
然后经过判别pointList
非空的前提下,将每个六边形的Path
创立出来并add
到pathList
中
这儿添加完pathList
之后还shuffle()
一下的原因是将pathList
打乱后,在遍历制作六边形的时分能够随机的选择格子来填充,而填充的时分,是先制作0个,然后制作数量递增下去直到pathList.size
,同样后边封闭屏保时分,数量也是从pathList.size
递减下去直到0,所以这个进程也能够用animateIntAsState
函数来创立
这儿新增一个开关pathState
,在dash
动画完毕之后翻开,将两个动画衔接在一起,而在Canvas
中制作六边形色块的时分,每次制作的数量不能超过pathIndex
,所以制作六边形色块的代码如下
现在再看下作用图
看到色块现已都填到格子里了,接下去便是让整个蜂窝墙布景色滚动起来
第四步:布景色滚动起来
现在是要让布景色出现一个多色突变而且滚动起来的作用,那么先将突变色值创立出来
这儿就来个四色突变,什么时分敞开突变呢?便是当色块都填充完毕的时分,所以再创立个开关,而且在色块填充完毕后翻开
当gradientColorState
开关翻开之后,在方才制作色块的地方加个逻辑判别,假如开关翻开就敞开突变,下面是代码与运转作用
然后是怎么让布景色转起来,Brush.linearGradient
的参数里边还有两个参数,别离是start
和end
,代表着突变方向,默许是从左上角到右下角方向,咱们能够经过不断改动start
与end
的值,来让全体作用看起来像是在旋转相同,改动的方式便是以画布中心会圆心,定长为半径,在一个圆周上不断得到对应的坐标点,这个点就作为start
,而在对应start
点的视点上加上180度计算出来的便是end
点,所以咱们需要一个0到360度的循环改动动画
然后运用gradientAngle
别离计算出start与end点,代入到Brush.linearGradient
函数中
全体作用就能让它滚动起来了
第五步:封闭屏保
刚刚咱们完成了翻开屏保的一切进程,现在咱们期望封闭屏保的时分,上述进程能够方向进行知道六边形格子消失,再退出程序,那么首先当封闭屏保的时分,switch
参数就变成false
了,咱们在这个时分就需要将布景色封闭,而且去除六边形色块
这儿else分支还加上gridSwitch.value == 1
的判别是为了防止程序一开始就进行封闭屏保的流程,然后当pathIndex
动画完毕的时分再将六边形格子的连接线动画封闭,那么格子的连接线就又会断开了
断开之后才是让格子从白色变回刚开始的通明色
最后当格子全部消失时分,就该退出程序了,这儿需要将事情传递给外面的Window
函数,然后去履行exitApplication()
操作,所以咱们给BeehiveWall
函数新增一个高阶函数的参数callback
,在格子消失之后调用callback
,那么事情就传递出去了
完好的一个敞开封闭的进程就出来了
然后再把整个布景弄成通明的,先把Canvas
的布景色去掉,然后在Window
函数中参加这些代码
这样就能保证咱们整个窗口是全屏加通明的了,咱们看下终究作用图
总结
这个蜂窝墙的屏保就算完成了,感兴趣的小伙伴能够把源码下下来然后自己改改样式玩玩看,后边假如想到其他有意思的屏保也会尝试做出来给我们看