1、属性介绍
在 iOS7.0之后出现了estimatedRowHeight这个属性,
@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
当我们在cell里面添加完所需控件,并约束好位置之后,我们只需要设置
// self-sizing技术 (iOS8 开始支持的),iOS8之后默认就是这个值,可以省略
// 告诉tableView所有cell的真实高度是自动计算的(根据设置的约束自动计算)
self.tableView.rowHeight = UITableViewAutomaticDimension;
// 告诉tableView所有cell的估算高度
self.tableView.estimatedRowHeight = 44;
就可以由系统自动计算高度。
那怎么样才算约束好呢?才能保证系统准确的计算出我们想要的高度呢?
2、子view布局要求
cell的布局核心:
cell的contentView的子视图支持起contentView,即每个子视图上下左右都要有约束,最后一个视图的bottom要设置的和contentView的bottom一样。这样宽高都有了,就可以自动进行约束了
[self.contentView addSubview:_contentLabel];
[self.contentView addSubview:_headerImage];
// 约束可以直接放在创建的地方
// 不要放在layoutSubviews 或 updateConstraints方法里
[_headerImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(10);
make.top.equalTo(self.contentView).offset(20);
make.height.width.equalTo(@50);
}];
[_contentLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_headerImage.mas_bottom).offset(5);
make.left.right.equalTo(self.contentView);
// 这一步是关键 让cell知道最底部在哪儿, 然后算出自身高度
make.bottom.equalTo(self.contentView);
}];
参考布局博文:
UITableViewCell高度自适应 使用Masonry纯代码约束
3、进一步理解自动计算高度
我想在大家初次解决tableViewCell高度自适应问题的时候应该会这样想过:在绘制cell的时候我们可以得到cell准确的高度,如果拿到这个高度设置成cell的高度不是刚刚好吗? 悲剧的是tableView显示数据的时候会先调用高度的协议方法(heightForRow...),然后才进行绘制(调用cellForRow...),也就是说,调用高度的时候cell可能都还不存在呢!
tableView: estimatedHeightForRowAtIndexPath:就是为了改变这个问题诞生的.我们用数据说话:当我们没有调用estimatedHeightForRow...这个方法的时候,tableView调用几个代理方法的顺序是这样的:(测试数据为5行)
可以看出,控制器在得知cell的行数n之后,会先一口气调用n次heightForRow方法,这是为了方便tableView计算自己的contentSize,进一步计算指示条的大小和位置.
在添加了estimatedHeightForRow...方法后,调用顺序变成了:
也就是说,愿望实现了. 这个方法的出现使得tableView代理方法的调用顺序发生了改变,从而达到了前面说的"绘制cell时得到准确高度,然后把高度再拿给tableView去显示"的目的.并且,这个方法避免了一开始调用n次heightForRow的方法导致的一些不必要的计算.
4、关于性能方面
可以参考博文[5]
其实在官方文档中已经有详细的介绍:
利用预估的高度,可以提升tableView的加载数据的性能。
那如果我们想要一部分cell需要手动计算高度,而另一部分cell需要自动计算高度,又该如何处理呢?
其实,关键在于以下核心代码:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 || indexPath.section == 1) {
return 81;
}
// 注意:解决固定行高和系统自动计算行高 其他组走系统自动计算行高
return UITableViewAutomaticDimension;
}
想用预估,直接返回UITableViewAutomaticDimension,否则返回计算的高度。追根溯源我们参考文档描述,如下:
参考博文:
- UITableViewCell高度自适应探索
- iOS UITableView 解决估算行高和指定行高的矛盾
- UITableView自动计算Cell高度思路
- UITableView高度问题
- iOS开发中行高灵活可变的UITableView的性能优化