TableViewCell高度自适应

相信很多朋友都深有体会,tableViewCell的高度计算的总是不尽人意

很多时候我们在项目中的cell会是多种多样的,当cell中含有高度不固定的文本labeltextView时怎么办

这里先列举几个之前的例子:

示例 : 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上我发现了这样一个库(喜欢钻研的人士可以传送门去瞧瞧):

  • UITableView-FDTemplateLayoutCell

一看简介着实吓了我一条 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

Masonry + 适配宏也很爽,配合labelsizeToFit瞬间轻松了,但是会发现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;
    

tableViewestimatedRowHeight 这个特性是在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中创建一个带Labelcell,label的高度不固定,其他上下左右约束需要约好,将这两行代码加入控制器中:

TableViewCell高度自适应_第1张图片
cell自适应

cell高度已经完美自适应了,值得注意的是,在这两行代码加入后,需要注释掉 heightForRowAtIndexPath因为一旦设置 heightForRowAtIndexPath将不会遵循 tableViewrowHeight

//-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//    
//}

另外如果出现高度还是不对的童鞋们,出现下方这种情况:

TableViewCell高度自适应_第2张图片
示例

请在xib中保证label的上下左右都有约束,不过有时候label虽然有约束但是同label进行约束的对象不固定,例如:

TableViewCell高度自适应_第3张图片
示例2

这个label针对下面View进行了bottom但是View却没有对点击查看有bottom的约束,(好像没有说的很明白)

可以用一个方法检测一下约束,保证xib是一块整体,当我们对cell进行拉伸时:

TableViewCell高度自适应_第4张图片
示例3

就会出现这种警告,其实我们是多加了针对点击查看对上面分割线的约束,虽然这条约束是多余的,但是保证了cell的高度被固定了起来,这样当我们再次运行的时候就会看到我们理想中cell的样子了,当然其实tableViewrowHeight 默认就是UITableViewAutomaticDimension,所以我们只要预估一下高度,并且约束好就可以达到高度的自适应了.

好了,这种方法是我一直在用的,避免了繁琐的高度计算,如果coder们有更好的提议,请评论私信我,觉得有用的请点个赞吧~

你可能感兴趣的:(TableViewCell高度自适应)