相信很多朋友都深有体会,tableViewCell
的高度计算的总是不尽人意
很多时候我们在项目中的cell
会是多种多样的,当cell
中含有高度不固定的文本label
或textView
时怎么办
这里先列举几个之前的例子:
示例 : One
小白一点的朋友们会发现当我们在cell
中进行高度计算然后return
高度,再在控制器中调用是不可取的,原因在于tableView
的代理方法heightForRowAtIndexPath
会在cellForRowAtIndexPath
之前调用
这个时候cell
还未创建,可能会导致程序的crash
, 调用类似于下面这种形式:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BaseModelCell *cell = [tableView cellForRowAtIndexPath:indexPath];
return [cell cellHeight];
}
示例 : Two
那cell
中不行,我们就在model
里赋值好了,很多时候我们的高度计算会在model
中长这个样子:
-(CGFloat)cellHeight{
UIFont *currentFont = [ThreePicModel currentFont];
CGRect labelrect = [self.title boundingRectWithSize:Size(WidthScale_IOS6(316), MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingTruncatesLastVisibleLine attributes:@{NSFontAttributeName:currentFont} context:nil];
if (iPhone5 || iPhone4) {
return labelrect.size.height+HeightScale_IOS6(170);
}else{
//计算出自适应的高度
return labelrect.size.height+HeightScale_IOS6(155);
}
}
然后在控制器中调用:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BaseModel *model = self.dataModelAry[indexPath.section];
return model.cellHeight;
}
当然,这种方法是可行的,只要判断做的足够多,我们的cell
呈现出来也是可以接受的,但是很多coder门已经厌倦了boundingRectWithSize
这个方法了,工作了的朋友估计也会遇到iOS8
系统下boundingRectWithSize
这个方法有时会导致crash
示例 : Three
我们还可以判断版本用创建方法计算,类似这个样子:
UILabel *textLabel = [[UILabel alloc]init];
textLabel.font = [UIFont systemFontOfSize:14];
textLabel.text = [self.user_id stringByAppendingString:[NSString stringWithFormat:@":%@",self.comment]];
textLabel.numberOfLines = 0;//根据最大行数需求来设置
textLabel.lineBreakMode = NSLineBreakByTruncatingTail;
CGSize maximumLabelSize = CGSizeMake(Screen_width - 88, MAXFLOAT);//labelsize的最大值
CGSize finalSize = [textLabel sizeThatFits:maximumLabelSize];
return finalSize.height;
coder们别喷我,我当年用过这个办法进行高度计算,而且我验证过,此方法计算出的高度比boundingRectWithSize
计算出来的高度更贴切
好啦~我知道致命的问题,这种方法,循环创建,什么工程也不会允许这么愚蠢的方法...
示例 : Four
那么还有什么方法呢?在github上我发现了这样一个库(喜欢钻研的人士可以传送门去瞧瞧):
一看简介着实吓了我一条 7000+
的star
简直要媲美我大MJ
了,当然网上有说利用这个库实现高度自适应是最屌的,我也觉得很厉害,下面开启传送门(ps
一下有玩炉石
的coder们么),在工程中使用大体是这个样子的:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) {
// 配置 cell 的数据源,和 "cellForRow" 干的事一致,比如:
cell.entity=self.feedEntities[indexPath.row];
}];
}
RunLoop
解决iOS 7以下高度问题
,这个库统统包含,可是我本人总是觉得工程中尽量少用第三方库,至少我们产品经理总是这样教育我们,那么还有什么方法呢?
示例 : Five
用Masonry
+ 适配宏
也很爽,配合label
的sizeToFit
瞬间轻松了,但是会发现cell
一般我们都是会用xib
进行创建,很少纯代码,至少我是这样,那还有没有更爽的方法了
[self.summaryLabel sizeToFit];
[self.summaryLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(Size(WidthScale_IOS6(28),HeightScale_IOS6(20)));
make.left.offset(space);
make.centerY.equalTo(self.mas_centerY);
}];
示例 : Six
看好了,如果你的项目适配的最低版本是iOS 8.0,那么接下来的两行代码将改变所有对于高度的计算:
self.tableView.estimatedRowHeight = 150;//估算高度
self.tableView.rowHeight = UITableViewAutomaticDimension;
tableView
的estimatedRowHeight
这个特性是在iOS 7
以后才存在,貌似在iOS 8
以后才少了许多7
中出现的bug
,比如在7
中你用这个estimatedRowHeight
会导致滚动条的大小处于不稳定的状态,contentSize
会随着滚动从估算高度慢慢替换成真实高度,这完全可以通过肉眼看出 (当然如果你的公司不适配7的话,你懂得😉)
我们看一下 estimatedRowHeight
官方文档给的解释
The estimated height of rows in the table view.
Providing a nonnegative estimate of the height of rows can improve the performance of loading the table view. If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.
When you create a self-sizing table view cell, you need to set this property and use constraints to define the cell’s size.
The default value is 0, which means there is no estimate.
大体意思是针对iOS 8
以后的,接下来是渣渣翻译
:
当你创建一个self-sizing表视图单元格时,你需要设置这个属性并且使用约束来定义单元格的尺寸。默认值为0,这意味着没有预估高度
OK,文档很清楚的说明了需要配合约束一起使用,那么我们可以试一下在xib
中创建一个带Label
的cell
,label
的高度不固定,其他上下左右约束需要约好,将这两行代码加入控制器中:
cell
高度已经完美自适应了,值得注意的是,在这两行代码加入后,需要注释掉heightForRowAtIndexPath
因为一旦设置heightForRowAtIndexPath
将不会遵循tableView
的rowHeight
//-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//
//}
另外如果出现高度还是不对的童鞋们,出现下方这种情况:
示例请在xib
中保证label
的上下左右都有约束,不过有时候label
虽然有约束但是同label
进行约束的对象不固定,例如:
这个label
针对下面View
进行了bottom
但是View
却没有对点击查看有bottom
的约束,(好像没有说的很明白)
可以用一个方法检测一下约束,保证xib
是一块整体,当我们对cell
进行拉伸时:
就会出现这种警告,其实我们是多加了针对点击查看对上面分割线的约束,虽然这条约束是多余的,但是保证了cell
的高度被固定了起来,这样当我们再次运行的时候就会看到我们理想中cell
的样子了,当然其实tableView
的rowHeight
默认就是UITableViewAutomaticDimension
,所以我们只要预估一下高度,并且约束好就可以达到高度的自适应了.
好了,这种方法是我一直在用的,避免了繁琐的高度计算,如果coder们有更好的提议,请评论
或私信
我,觉得有用的请点个赞吧~
网友评论
第五种方法还是最简单,性能最高的.但是其实有 bug, 在 6p 屏幕上大量文字会出现空白的地方
跟您解释一下
拿我例子的xib来说
如果想实现使用estimatedrowheight 简单来讲所有控件的上下约束都应该存在
但例子中 点击查看 和上面的线 只是针对cell的底来约束的就可以确定位置 但没有跟自适应高度label有约束 所以即使label是自适应的 这个cell整体的高度还是不确定的 说到这不知道您理解了么
所以我们需要把那条线跟label加一条约束 虽然这样cell的高度在xib中会被固定 所以会出现一改变xib的cell总高度就会爆红 但实际上它还是自适应高度
目前没找到解决办法 可能还是约束的不到位 望理解