以前写TimeLine中照片九宫格布局是直接计算frame,今天想用自动布局实现。
九宫格布局
使用自动布局,首先就必须知道给出了哪些条件。一般在TimeLine中照片九宫格布局给出的已知条件为:
- 每个单元的宽cellWidth;
- 每个单元的高cellHeight;
- 每行有几个单元numPerRow;
- 总共单元个数totalNum;
- 每个单元与边界间距viewPadding;
- 每个单元之间的间距viewPaddingCell。

图 1是一个九宫格,黄色区域为父视图,由已知条件可知,它的大小是由里面的单元格布局决定的,所以,只要固定住里面的单元格,父视图就会自动固定住。
下面我们来添加约束:
1.所有单元格添加高度(height)和宽度(width)约束,如图 2所示,

2.第一行相对父视图,添加top约束,如图三中紫色箭头所示,

3.非第一行添加对上一行单元的top约束,如图四红色箭头所示,

4.第一列添加对父视图的left约束,如图五墨绿色箭头所示

5.非第一列添加对上一个view的left约束,如图6深蓝色箭头所示

这时候你会发现所有单元格都固定了,但是父视图的大小却不能固定,因为还不能得出父视图的宽和高
6.右上角(第一行&最后一列)添加对父视图right约束,如图7所示,2号单元格右侧绿色箭头

7.左下角(最后一行&第一列)添加对父视图的bottom约束,如图8所示,6号单元格底部紫色箭头

talk is cheap show me the code.

1 |
|
代码中有一些判断,比如是否为第一行,
1 | /** |
是否为第一列,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
是否第一列
@param index 当前下标
@param numOfRow 每行个数
@return YES OR NO
*/
- (BOOL)isFirstColumnWithIndex:(NSInteger)index numOfRow:(NSInteger)numOfRow
{
if (numOfRow != 0)
{
return index%numOfRow == 0;
}
return NO;
}
是否为最后一行,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/**
是否最后一行
@param index 当前下标
@param numOfRow 每行个数
@return YES OR NO
*/
- (BOOL)isLastRowWithIndex:(NSInteger)index numOfRow:(NSInteger)numOfRow totalNum:(NSInteger)totalNum
{
NSInteger totalRow = ceil(totalNum/((CGFloat)numOfRow));//总行数
if (numOfRow != 0)
{
return index/numOfRow == totalRow - 1;
}
return NO;
}
是否为最后一列
1 | /** |
注意:这里有个地方要注意,当你的单元格总数(totalNum )小于每行个数 (numOfRow),比如总共有2个单元格,每行排三个,那么最后一个即为最后一列。
上面这四个判断在很多地方都可以用到,可以记下备用🙂。
然后是上一行的view判断也需要注意。
其实这不单单只是九宫格布局,N个单元格布局也是可以的,感兴趣的小伙胖可以自行测试(好吧,估计你从我写的方法名已经看出来了,每行个数和总个数我都没有写死😂)。
另一种九宫格
这里的九宫格布局是子视图固定,而父视图由子视图决定,还有另一种情况:父视图高宽固定,子视图与父视图边界距离给定,子视图间距给定。
知道怎么布局吗?可以先思考一下。
|
|
|
|
|
|
好吧,揭晓答案:只要按照第一种九宫格前5个步骤来添加约束即可,去掉最后两步。
总结
一开始我只是想布局一个九宫格,但是后来又想,如果需求扩展到了N个单元,该如何实现呢,我的办法是从九宫格开始,由小及大来推导,然后就是要知道自动布局需要添加哪些约束,能够完整的固定视图,不能多,也不要少,这是很重要的。