实现球随机布局
最近碰到一个需求,需要在界面上随机出一些大小、颜色、位置随机的球(圆形按钮),并能够保证视觉效果好看,并且可以切换上一屏和下一屏附带动画,针对该需求想了很多方法,写该篇文章记录下来
效果如下图:

代码地址:GWCircleLayoutBall
分析
拿到上面UI图后,首先分析UI的需求,有以下规律:
- 球有随机一共5种大小
- 球颜色各不相同
- 最多有两个球相交,并且小部分相交
- 有一个球在靠近中心点位置,并大小偏大
- 切换到下一屏时重新随机不同位置的球,上一屏球移出动画
- 切换到上一屏时,当前屏球透明消失,上一屏从屏外移回到以前的位置
第一个想到的是使用UICollectionView实现圆形布局,但是除中心球外,外面的球并不在圆上面,而且四周的球可能离相同圆弧很远。根据所有的布局和代码问题都应该抽象成一个数学问题的思路,最后发现要保证UI的协调和好看,需要保证球的随机错落分布的同时保证球整体是均匀分布的。
最后得到一个思路,从中心点出发,在屏幕上绘制圆形轨道,第一个球在第一个小圆的轨道上偏移,随后的球在之后的轨道上随机均匀分布;其次为了让球随机分布,看不出在同一个圆的轨道上,应该给每一个球一个中心点偏移量。
大概如下图:

为了保证随机的同时均匀分布,则应该圆轨道上第一个球随机位置,然后同一个圆上面其它位置球相对在一定范围内随机。该圆形轨道的下一个轨道上,则根据该轨道第一个球进行一定范围内便宜,就像是内圈的球组成一个三角形,下一个轨道上也组成一个三角形,形成一定偏移。
具体实现思路:
- 在屏幕上计算圆形轨道,存储圆形轨道半径数组
- 球随机位置通过随机角度来实现,随机一个角度,通过圆形点和角度计算出球中心的位置,对中心位置给一个范围内的随机偏移
- 第二个球也随机一个角度,然后随机一个大小,放到第二个轨道上。
- 大于第一层并且不是该层第一个球则获取前一个球的角度,计算平均角度值(360 / 球个数)然后随机一个角度偏移量,计算出该球位置
- 大于第二层轨道的球,为了保证不与前一层轨道的球重叠,则该轨道第一个球先获取前一层第一个球的角度,在该角度基础上随机一定范围的角度偏移
这其中涉及到两个问题:
- iOS中随机一个范围内的值
- 根据中心点和角度计算坐标点
上面这两个问题,网上都有现成的代码。
下面直接上代码:
1 | /** |
首先定一个Model类来保存球即圆形按钮的布局相关参数,其中出现位置和移动位置后面做交互动画用
1 | @interface CircleButtonModel : NSObject |
核心是如何去随机球的位置,要移出屏幕的位置等,球的位置由球的下标计算出球所在的圆弧,然后根据半径,随机的角度,中心偏移量计算出位置坐标;移出的坐标则是通过计算球中心所在的象限,斜着飞出屏幕。代码如下:
1 | - (NSArray *)createButtons{ |
动画
在随机球的基础上加上随机上下的动画,类似漂浮的动画,让界面更好看。
思路是:让球的中心在一个随机的范围内上下移动,并且每个球的上下动画随机,形成错落有致的视觉效应。
代码如下:
1 | /** |
交互动画
交互动画主要是切下一屏和切上一屏
切下一屏动画组成
- 点击的球逐渐变小和变透明然后消失
- 根据之前计算的球要移出屏幕的坐标分别做位移动画
- 下一屏的球从点击的球中心点出现,做大小和位移动画
1 | - (void)showNextButtons{ |
切上一屏动画组成
- 点击的球逐渐变小和变透明然后消失
- 当前屏的球透明变小消失
- 上一屏的球从屏外移回之前的位置
1 | - (void)showPreButtons{ |
这个UI和之前做的UI布局方式不太相同,
运用了很多数学只是和大量动画,数学在编程中真的非常重要。