中心点
iOS8后面,其实啥也不用干。最核心的做了下面两点,就能达到cell自适应高度:
- 需要添加cell的子视图的约束
top, bottom,left,right
。 - 不要实现
UITableViewDelegate
中,任何返回cell高度的代理方法:- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
先说总结出的三种可行方式
-
代码
写布局控件:-
cell
要自定义 - 满足上面两个核心条件
-
tableView.estimatedRowHeight
的预估值,可以让cell
复用率提高,节省内存。
-
-
xib
写布局:-
xib
创建一个cell
。(本身就是自定义了一个cell)
- 满足上面两个核心条件
- 一直创建新的cell,如果数据非常非常多,要考虑内存问题
-
- 如果
cell
里面只装载文字,直接用系统UITableViewCell
自带的text label
,cell复用率最高。 但使用场景低。
问题
光是实现上面两个核心要件,也不能任意场景下,完美实现cell
自适应高度,还有一些事情是需要厘清的。
-
tableView.rowHeight = UITableViewAutomaticDimension
和tableView.estimatedRowHeight = 10
,起了什么作用。 -
纯代码
使用系统UITableViewCell
,创建一个label
,添加到系统UITableViewCell
,最后导致所有cell 高度一致
-
纯代码
使用系统UITableViewCell
,并使用系统UITableViewCell
中自有的textlabel
,复用率最高,而且高度不复用,效果完美 -
纯代码
使用自定义cell
,能够避免cell的高度复用
,原因是不是cell没有复用
? -
xib
使用自定义cell
,也能最简单
,没有坑
的实现cell高度自适应,并且避免了高度一致
,原因是不是也是cell没有复用
? - 使用
masnory
和原生NSLayoutConstraint
,结果有什么区别?
探索
1. 设不设置tableView.rowHeight = UITableViewAutomaticDimension
,有什么影响?
- 点开系统
UITableView.h
,可以看到
系统默认的就是@property (nonatomic) CGFloat rowHeight; // default is UITableViewAutomaticDimension
UITableViewAutomaticDimension
2. 设不设置tableView.estimatedRowHeight = xxx.0f
,有什么影响?
- 其实这个值设置多少,影响还是有的。用下面个例子证实:
- 一个
array
包含12
个字符串,用label
显示。 - 设置
label.numberOfLines=0
-
纯代码自定义的cell
中添加label
,并且添加label
上下左右约束。 - 在下面方法中断点
if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid]; }
tableView.estimatedRowHeight = 任意值
- 一个
- 可以看到,随着
tableView.estimatedRowHeight
值的变化,上面断点的次数也会不一样,最多会有13次的断点。最少会有当前屏幕cell
个数+1的次的断点。这说明了,cell
复用次数,居然不一定了?那就只能一个原因:- 当
tableView.estimatedRowHeight
的值,可以让label把所有字符串显示出来,系统就会到cell复用池
去寻找符合这个高度的cell
。如果有,就复用,如果没有就重新创建。 - 当设置
tableView.estimatedRowHeight = 1
时,明显这个高度不能让任何label完全显示,这个时候,就会发现,上面断点走了13
次,而整个array
只有12
字符串元素。这就说明cell
没有任何复用!
- 当
-
补充一点:estimatedRowHeight不仅是设置预估值,也是一个阈值,当=<0的时候,实际上是禁用掉estimatedRowHeight 预估高度的功能
,某些iOS版本下,禁掉此功能,会导致cell=默认高度44,从而引起约束冲突
3.用纯代码
创建一个label,添加在 系统UITableViewCell
中,并添加上下左右约束,高度复用
- 同样在
cell==nil
的条件中打上断点,发现断点次数永远是当前屏幕显示的cell的个数+1
,同时滚动几次,12个cell高度一样,这说明了,使用系统UITableViewCell
基础上,代码自定义label
,cell复用率最高,但是高度最后也会一样,这样的效果,现实项目中根本不能用。
4.使用系统UITableViewCell
中的自有的textlabel
装载array
的元素字符串,并设置textlabel.numberOfLines=0
,cell
复用率最高,且高度不会复用,效果完美。
- 这种效果从内存优化角度,和高度自适应角度,效果是最好的。可是
系统UITableViewCell
自带的textlabel
,使用场景很低很低,稍微复杂的项目,就不能用。 - 可是为什么
自定义一个label
,就会高度复用?没搞明白。
5.用纯代码
创建一个label,添加在自定义Mycell
中,并添加上下左右约束,效果完美,但是有没有复用?
- 在
tableView.estimatedRowHeight=0
时候,发现断点次数永远是array.count+1
次, -
tableView.estimatedRowHeight
的值能够让某个lable完全显示字符串,断点次数就比array.count+1
少了。 - 结论:明显不设置
tableView.estimatedRowHeight
,xib
创建一个cell
是没有复用。之所以有时候复用,完全是tableView.estimatedRowHeight
的值设置恰当。
6. 用xib
创建一个cell
,拉好控件label,拉好上下左右约束,原因是不是也是cell没有复用
?
- 这种方式一直滚动,一直断点,跟
tableView.estimatedRowHeight
的值没有关系。 - 结论:
xib
自定义cell,会一直创建新的cell。因此高度永远不会一致。
7.用masonry
和原生NSLayoutConstraint
,有什么区别?
- 没有任何区别,需要注意的是,masnory内部设置了
label.translatesAutoresizingMaskIntoConstraints = NO
。用原生NSLayoutConstraint
,要加上一句label.translatesAutoresizingMaskIntoConstraints = NO
结论
-
tableView.rowHeight = UITableViewAutomaticDimension
设不设置,毫无影响。 -
纯代码
下:-
自定义tableViewcell
装载字符串,tableView.estimatedRowHeight
的值,会决定cell
复用的次数。 - 在
系统UITableViewCell
中添加自定义label
装载字符串,tableView.estimatedRowHeight
的值,会决定cell
复用的次数,而且cell的高度
也会复用,一直滚动,最后所有cell高度一致。这个方式几乎可以抛弃。
-
- 使用
系统UITableViewCell
又分两种情况:- 一种使用
系统UITableViewCell
自带的textlabel
,效果好,使用场景低。几乎用不到。 - 一种自定义
label
添加到系统UITableViewCell
上,高度也会复用。这个方式几乎可以抛弃 -
系统UITableViewCell
自带的textlabel
既然能无bug实现,自定义label
肯定也能完美实现,只是还没找到原因。
- 一种使用
-
xib
创建一个自定义tableViewcell
,会一直创建新的cell
。结果高度肯定也不会复用。 - 使用
原生NSLayoutConstraint
添加约束时,注意设置label.translatesAutoresizingMaskIntoConstraints = NO