TableViewCell高度自适应

作者: 被帅醒的小吴同志 | 来源:发表于2017-01-08 18:31 被阅读6407次

    相信很多朋友都深有体会,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上我发现了这样一个库(喜欢钻研的人士可以传送门去瞧瞧):

    一看简介着实吓了我一条 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 + 适配宏也很爽,配合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的高度不固定,其他上下左右约束需要约好,将这两行代码加入控制器中:

    cell自适应
    cell高度已经完美自适应了,值得注意的是,在这两行代码加入后,需要注释掉heightForRowAtIndexPath因为一旦设置heightForRowAtIndexPath将不会遵循tableViewrowHeight
    //-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    //    
    //}
    
    

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

    示例

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

    示例2

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

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

    示例3

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

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

    相关文章

      网友评论

      • deqiutseng:我对 点击查看表示好奇,刚好我现在要实现这样的功能一直没有找到好的解决办法,我现在想实现点 点击查看 展开详情信息,再点 进行伸缩, 示例 : Six 这种方式也可以做到么?
      • 码农淏:最后一种每次都要算高度滴.影响性能的.自己缓存下行高还行.
        第五种方法还是最简单,性能最高的.但是其实有 bug, 在 6p 屏幕上大量文字会出现空白的地方
      • 阿唯不知道:老铁,我爱死你了,我想把菊花献给你!太他么牛皮了,钟爱:示例 : Four,示例 : Six
        阿唯不知道:@被帅醒的小吴同志 虽然基础,但是实用呀:blush:
        被帅醒的小吴同志:@阿唯不知道 淡定 淡定 能帮助你就好 这篇文章其实挺基础的 没写一些cell高度缓存的策略什么的 :blush:
      • apologize1821:性能会有问题,如果页面复杂 不做缓存 肯定会出现卡顿问题。
      • 独白melody:coder届玩炉石最屌的在此。另外我想问一下,iOS11是不是已经会自动自适应cell高度了?
      • 风飞燕:很不错
      • 莪笨善良:enmmmmm,说个意见,现在很多应用应该都很少用xib吧,虽然方便,但是也很容易出现各种警告,而且像ios10升级到11的时候,打包的过程中,xib会出现很多问题,所以还是代码稳当吧
        被帅醒的小吴同志:实际上自动设置估算高度跟xib没关系,只要是用autolayout布的局就可以适用,当然代码更推荐Mansory不就好了,底层都是autolayout嘛。一样的
      • 64c1ea3d14d4:我特意注册简书来写下这个评论,我在搜ReactiveCocoa一个东西的时候,不知道为什么会跳出来这个文章,很好奇有什么新鲜的方法点了进来。我只想告诉你,你写的这个方案真不是现阶段最好的自适应计算的最好方法。在以前做项目,使用masonry和这个库的时候产生过bug,所以弃用了,具体忘记了,反正卡顿或者字体超出框什么一类,你多用用就会发现问题,现阶段我找到最好的方法是MyLinearLayout这个库,希望你有空看一下,也不用回复我,我也不用简书,善意提醒你。
      • 名字难取Jay:你好,其余内容看懂了,但是关于(另外如果出现高度还是不对的童鞋们,出现下方这种情况:)这句话底下的内容没有看懂,特别是图片显示的检测一下约束那一部分没有理解,请问有实力代码供参考下吗?
        被帅醒的小吴同志:@e985d3a9a2e7 您好 我发现我确实表达的不够清楚
        跟您解释一下
        拿我例子的xib来说
        如果想实现使用estimatedrowheight 简单来讲所有控件的上下约束都应该存在
        但例子中 点击查看 和上面的线 只是针对cell的底来约束的就可以确定位置 但没有跟自适应高度label有约束 所以即使label是自适应的 这个cell整体的高度还是不确定的 说到这不知道您理解了么
        所以我们需要把那条线跟label加一条约束 虽然这样cell的高度在xib中会被固定 所以会出现一改变xib的cell总高度就会爆红 但实际上它还是自适应高度
        目前没找到解决办法 可能还是约束的不到位 望理解
      • Roader:这个库是sunny在百度时和他的开源团队写的,是很牛逼呢!
      • 95114676ad51:最后一种,自动计算高度,滑动起来有明显卡顿的感觉,楼主是怎么解决的?
        被帅醒的小吴同志:@祖师爷 应该不会卡顿吧 你设置一下预估高度 想差不太多应该不会有明显卡顿的 如果还是存在试着做一下高度缓存吧
      • 2c8aea30e451:對於懶惰的coder 而言,autolayout 太麻煩了,以致不能用這個功能:disappointed_relieved:
        被帅醒的小吴同志:@kinGwL mansory 一样可以用
      • 十一岁的加重:iOS8以后,垂直约束,自动估算
        代码DJ:但是上拉加载更多的问题,如果用autolayout,明显不行,reloadData 会跳动
        十一岁的加重:@Kevin20481 新手
        Vincent20481:@十一岁的加重 你说的是xib吧?
      • skycolor:很棒啊
        被帅醒的小吴同志:@skycolor 谢谢支持
      • Lol刀妹:可以:rabbit:
        被帅醒的小吴同志:@无夜之星辰 感谢支持:pray:

      本文标题:TableViewCell高度自适应

      本文链接:https://www.haomeiwen.com/subject/sxoqbttx.html