距离上次做飘动的小球的屏保现已过去了一个多月,发现那些小球看多了也腻,可是想再做个屏保么也没啥思路,可是前阵子在陪娃看了个新出的动画片,叫啥量子战队的,里边主角总部的墙引起了我的留意,那是一个个小格子,每个格子是六边形形状,就像蜂窝相同,然后全体色彩还会慢慢改动,这一下子灵感就挠得一下就上来了,我也来撸个蜂窝墙出来

源码地址

规划思路

全体的一个规划进程分以下几步

  1. 整个进程分为翻开屏保与封闭屏保
  2. 翻开屏保的时分,首先展示一个蜂窝墙的一个架子
  3. 架子展示完之后,逐步给一个个蜂窝格子填充色彩
  4. 填充完色彩之后,整个蜂窝墙布景出现一个多色突变而且布景顺时针旋转
  5. 封闭屏保时,上述进程反向操作,终究退出程序

第一步:先做屏保开关

Window函数中创立一个MenuBar,而且里边有两个Item,别离用来履行翻开与封闭屏保的操作,咱们在创立一个switch变量,并让它作为参数传入屏保的Compose函数中,点击Item的时分,改动switch的值,代码如下

又想做屏保了,这次用Compose做个蜂窝墙

第二步:蜂窝墙架子

一个蜂窝墙架子,其实便是一个六边形的网格布局,平时让咱们画一个圆点布局,会画,画一个正方形格子布局,也能画,可是六边形布局咋画呢,DrawScope里翻了一圈也没找到对应的Api,那么只能“徒手画”了,先剖析下六边形网格布局的特点,它看起来是由若干个点朝着圆周上三个方向延伸出去三根直线,当每一个点的三根直线与其他点的三根直线重合的时分,一个六边形网格布局就形成了,咱们只需要将这些点找出来,然后在根据视点计算出延伸方向的终点坐标,将两点连起来就好了,听起来像是这么一回事,可是先看看下面的图

又想做屏保了,这次用Compose做个蜂窝墙

咱们看到中间的横线左右两个端点延伸出去的直线,视点是不相同的,也便是说咱们不只要找出一切的点,还必须确认好每一个点延伸出去的方向才能制作不同的直线,那这个工作量无疑是庞大的,咱们得找找其他方案,得找出一个固定不变的制作规则,有吗?咱们再看看下面这张图

又想做屏保了,这次用Compose做个蜂窝墙

这是一个六边形网格布局的一部分,咱们看中间那个六边形,这个六边形的中心点咱们用黑色标出来了,咱们发现这个黑点到六边形六个角的视点别离为0,60,120,180,240,300,而且每一个六边形都有这样的规则,那么咱们是不是能够找出一切六边形的中心点坐标,然后计算出六个角的点坐标,而且将相邻的视点计算出来的坐标连起来,六边形布局就完成了呢,那么先创立出一个寄存视点的数组,以及六边形的边长

又想做屏保了,这次用Compose做个蜂窝墙

anglist便是寄存视点的数组,而radius便是六边形的边长,同时也是中心点到每一个角的距离,接下来便是思考下怎么将一切的中心点找出来,咱们再看看下图

又想做屏保了,这次用Compose做个蜂窝墙

请无视我粗糙的画功,咱们将之前那张图补充点元素便是上面这个图,其间第一排与第三排的中心点,它们第一个点都与画布边距一个radius的距离,紧接着便是3 * radius的距离递增,而第二排与第四排的中心点略有不同,第一个点没画出来,它在画布外面,与画布边距是负的0.5 * radius的距离,然后也是3 * radius的距离递增,经过这些能够将中心点的横坐标确认下来

又想做屏保了,这次用Compose做个蜂窝墙

xUnit为中心点之间横坐标的距离,xLength是单排横向上的格子数量,加一是为了防止边上出现不完好的格子,xListxList2是单排与双排的横坐标数组,咱们再来看看上图来确认纵坐标,两个中心点的纵向距离为两倍的中心点到六边形底部的距离,那这个距离怎么算呢,咱们运用勾股定理就能算出来,radius的平方减去一半radius的平方开根号就得到了,代码如下

又想做屏保了,这次用Compose做个蜂窝墙

yUnit便是咱们刚刚运用勾股定理算出来的两点纵向距离,yLengthxLength相同,加上一防止有不完好的格子出现,yListyList2是单列与双列的纵坐标数组,现在就能够经过遍历单排单列坐标与双排双列坐标将一切六边形画出来了

又想做屏保了,这次用Compose做个蜂窝墙

其间pointXpointY函数是用来经过半径,中心点与视点计算出终点横纵坐标,代码如下

又想做屏保了,这次用Compose做个蜂窝墙

运转一遍程序之后,就获得了咱们蜂窝墙的一个架子了

又想做屏保了,这次用Compose做个蜂窝墙

现在咱们结合之前做好的开关,让这个架子能够在翻开开关之后才出来,那么未翻开的时分网格便是通明色的,翻开才是白色,所以这儿有个色彩的过渡进程,咱们运用animateColorAsState函数来完成

又想做屏保了,这次用Compose做个蜂窝墙

这儿新建了一个Int的变量gridSwitch来作为咱们动画的真实开关,当不为0的时分,格子色彩永远是白色,这样做的目的是为了当咱们封闭屏保的时分,假如直接运用布尔变量switch,那么就会直接让格子消失,就不会有规划思路里边说的将翻开动画反向再履行一遍的进程,现在咱们将gridColor代入到drawLine的函数里边,就初步得到一个翻开网格的进程

又想做屏保了,这次用Compose做个蜂窝墙

现在在网格出现的时分增加一个作用,现在咱们看到的是整个网格都展示出来,现在只让网格的穿插点先出来,等穿插点出来之后,两点之间再延伸出一根白线将点连在一起,怎么做呢?是动态改动drawLinestart点或者end点吗?不是的,咱们这儿运用PathEffect里边的dashPathEffect函数,这个函数看名字就知道是用来画虚线的,怎么画呢,看下它源码里边咋说的

又想做屏保了,这次用Compose做个蜂窝墙

一大堆注释,概括一下便是这个函数需要传入两个参数,第一个参数intervals是一个float数组,一般这个数组里边放两个值,第一个是实线长度,第二个是实线间的距离大小,第二个参数phase,感觉这个命名改成offset更适宜,意思便是制作线的起始位置朝反方向挪动phase距离,默许是0,那么我先用PathEffect给网格的线加个虚线作用试试

又想做屏保了,这次用Compose做个蜂窝墙
又想做屏保了,这次用Compose做个蜂窝墙

这儿给虚线作用设置的是实线长为10,距离长也为10,原因是咱们单条线的radius之前是现已设置好了30,所以距离与实线长度联系是实线长度=(radius-距离长)/2,当距离长刚好等于radius的时分,那么只剩穿插点,没有线了,反之当距离为0的时分,那么距离就看不到了,经过这两个临界值以及实线与距离的联系,咱们能够做出一个点与点相连变成网格的动效

又想做屏保了,这次用Compose做个蜂窝墙

咱们给虚线的动效新建个开关dashState,而且在gridColor动画完毕之后,将dashState开关翻开敞开连接动画,另外将dash代入到制作drawLine函数中

又想做屏保了,这次用Compose做个蜂窝墙
又想做屏保了,这次用Compose做个蜂窝墙

第三步:给蜂窝填充色彩

这儿的填充色彩不是简略的将整个画布设置个色彩就完事了,而是需要在每一个格子都设置个色彩进去,那么问题来了,咱们之前画格子是只画了线,格子内部其实是啥也没有的,所以与其说是填充色彩,还不如说是画一个带色彩的六边形,还是逃不了啊,那就只能画了,之前说drawScope里边没有现成的api来画六边形,那么咱们能够多走一步,经过制作Path来形成六边形,道理也是相同的,先是moveTo到一个点,然后drawLine到下一个点,一圈下来也是个六边形了,那么第一步,需要收集好一切六边形的中心点,这样才能达到能够在随意一个位置就画六边形的作用

又想做屏保了,这次用Compose做个蜂窝墙

这儿的pointList便是拿来放一切中心点的数组,pathList用来寄存终究制作六边形Path的数组,然后咱们在制作六边形格子的时分,顺便将每个中心点add到这个pointList里边去,像这样

又想做屏保了,这次用Compose做个蜂窝墙

然后经过判别pointList非空的前提下,将每个六边形的Path创立出来并addpathList

又想做屏保了,这次用Compose做个蜂窝墙

这儿添加完pathList之后还shuffle()一下的原因是将pathList打乱后,在遍历制作六边形的时分能够随机的选择格子来填充,而填充的时分,是先制作0个,然后制作数量递增下去直到pathList.size,同样后边封闭屏保时分,数量也是从pathList.size递减下去直到0,所以这个进程也能够用animateIntAsState函数来创立

又想做屏保了,这次用Compose做个蜂窝墙

这儿新增一个开关pathState,在dash动画完毕之后翻开,将两个动画衔接在一起,而在Canvas中制作六边形色块的时分,每次制作的数量不能超过pathIndex,所以制作六边形色块的代码如下

又想做屏保了,这次用Compose做个蜂窝墙

现在再看下作用图

又想做屏保了,这次用Compose做个蜂窝墙

看到色块现已都填到格子里了,接下去便是让整个蜂窝墙布景色滚动起来

第四步:布景色滚动起来

现在是要让布景色出现一个多色突变而且滚动起来的作用,那么先将突变色值创立出来

又想做屏保了,这次用Compose做个蜂窝墙

这儿就来个四色突变,什么时分敞开突变呢?便是当色块都填充完毕的时分,所以再创立个开关,而且在色块填充完毕后翻开

又想做屏保了,这次用Compose做个蜂窝墙

gradientColorState开关翻开之后,在方才制作色块的地方加个逻辑判别,假如开关翻开就敞开突变,下面是代码与运转作用

又想做屏保了,这次用Compose做个蜂窝墙
又想做屏保了,这次用Compose做个蜂窝墙

然后是怎么让布景色转起来,Brush.linearGradient的参数里边还有两个参数,别离是startend,代表着突变方向,默许是从左上角到右下角方向,咱们能够经过不断改动startend的值,来让全体作用看起来像是在旋转相同,改动的方式便是以画布中心会圆心,定长为半径,在一个圆周上不断得到对应的坐标点,这个点就作为start,而在对应start点的视点上加上180度计算出来的便是end点,所以咱们需要一个0到360度的循环改动动画

又想做屏保了,这次用Compose做个蜂窝墙

然后运用gradientAngle别离计算出start与end点,代入到Brush.linearGradient函数中

又想做屏保了,这次用Compose做个蜂窝墙

全体作用就能让它滚动起来了

第五步:封闭屏保

刚刚咱们完成了翻开屏保的一切进程,现在咱们期望封闭屏保的时分,上述进程能够方向进行知道六边形格子消失,再退出程序,那么首先当封闭屏保的时分,switch参数就变成false了,咱们在这个时分就需要将布景色封闭,而且去除六边形色块

又想做屏保了,这次用Compose做个蜂窝墙

这儿else分支还加上gridSwitch.value == 1的判别是为了防止程序一开始就进行封闭屏保的流程,然后当pathIndex动画完毕的时分再将六边形格子的连接线动画封闭,那么格子的连接线就又会断开了

又想做屏保了,这次用Compose做个蜂窝墙

断开之后才是让格子从白色变回刚开始的通明色

又想做屏保了,这次用Compose做个蜂窝墙

最后当格子全部消失时分,就该退出程序了,这儿需要将事情传递给外面的Window函数,然后去履行exitApplication()操作,所以咱们给BeehiveWall函数新增一个高阶函数的参数callback,在格子消失之后调用callback,那么事情就传递出去了

又想做屏保了,这次用Compose做个蜂窝墙
又想做屏保了,这次用Compose做个蜂窝墙

完好的一个敞开封闭的进程就出来了

然后再把整个布景弄成通明的,先把Canvas的布景色去掉,然后在Window函数中参加这些代码

又想做屏保了,这次用Compose做个蜂窝墙

这样就能保证咱们整个窗口是全屏加通明的了,咱们看下终究作用图

又想做屏保了,这次用Compose做个蜂窝墙

总结

这个蜂窝墙的屏保就算完成了,感兴趣的小伙伴能够把源码下下来然后自己改改样式玩玩看,后边假如想到其他有意思的屏保也会尝试做出来给我们看