iOS cell高度自适应 - 教你写出优雅的table view

作为一个iOS开发者,自然少不了了table view打交道,table view中最令人头疼的是各种cell的高度计算了,虽然技术上并不难,但是对于自定义cell来说一旦控件比较多,计算起来就会很麻烦,会出现很多和height相关的代码,万一稍有偏差,就要小心老板和测试大虾们鄙视的小眼神了。
今晚呢,现在已经是凌晨了~
下面就为大家介绍一种方法,让你的cell彻底丢弃HEIGHT这玩意儿~

在正式介绍之前,你需要了解约束,如果你熟练运用autolayout或者Masonry这等玩意儿写约束,那么你就可以轻松理解下面的讲述了。如果你意识到这两个东东不认识你,那么爱学习的你要利用好网络,去搜索一下Masonry或autolayout,很多大虾讲过着玩俩玩意儿,也很好学,个人推荐Masonry。


下面开始干货

首先介绍UITableViewDelegate中的一个方法

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);

这货是iOS 7之后出现的,作用是返回一个估算的cell高度,如果你的应用支持iOS 7以及之后的版本,那就你就可以高枕无忧的愉快使用了。
按照正常的步骤来说,table view会先走heightForRow方法去获取高度,然后走cellForRow方法去初始化和赋值等。但是一旦你的代码中出现了这货,他俩的执行顺序就颠倒了,先执行estimatedHeightForRow,其次执行cellForRow,再执行heightForRow,可以见得heightForRow的作用被弱化了。
通过下面的讲解,你就会知道heightForRow岂止是被弱化了,这东西几乎要被抛弃了。


下面以一个最简单的例子讲解怎样去除恼人的高度计算(讲解、代码和demo基于Masonry)
分析一下,这个cell中包含两个label和一个view,一个是显示在上面的title label(“row : 2 …”),一个是显示在下面的detail label(“生活如此美好 …”),一个是最底下的灰线。
iOS cell高度自适应 - 教你写出优雅的table view_第1张图片

  1. cell中各个控件,先找出有上下关系的,如此cell中title label、detail label和灰线。
  2. 将有上下关系的控件的top和bottom约束好,例如这个cell中,title label在detail label上面距离其顶部x,detail label 在灰线上面,距离灰线顶部y。
  3. 最为关键的点:给最上面的title的top和最下面的灰线的bottom添加相对于父视图的约束
  4. 最后愉快的删除heightForRow并写上estimatedHeightForRowAtIndexPath方法,return一个你喜欢的数字(当然越接近真实值越好)
    • //label的高度就不需要操心了,因为它会根据内容的多少自适应,这也是之前计算label高度的关键
这里给出上面cell中三个控件的约束代码
 /**
        请仔细看两个控件之间以及它们和父视图的约束,主要是top和bottom之间的约束
        1、titleLab在上面,距离父视图上方和左边各10像素
        2、detailLab在titleLab下面,距离titleLab 8像素,左边和titleLab对齐,切底部距离bottomLine 10像素
        3、bottomLine在最下面,左右和底都和父视图对齐,高度为1
     Label是个好玩的东西,如果有文本,则label有高度,如果内容为空,则高度为0,我们就是利用了它们的这个特性来省区计算高度的步骤
     * 当然,为了使其能自适应高度,我们一般会把label的宽度约束死
     * 代码中重点约束已标注 “//重点”
     */

    [self.titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.equalTo(self).offset(10);//重点
        make.right.equalTo(self).offset(-15);
    }];
    [self.detaiLab mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.titleLab);
        make.top.equalTo(self.titleLab.mas_bottom).offset(8);//重点
    }];
    [self.bottomLine mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.detaiLab.mas_bottom).offset(10);//重点
        make.bottom.left.right.equalTo(self); //重点
        make.height.mas_equalTo(1);
    }];

通过上面三个步骤,cell以及其中的三个控件的上下约束已经完成。现在给title label和detail label填充内容,它们的高度随文字自适应,那么cell的高度也会随着label的高度的改变而改变(因为它们之间的上下关系已经约束好了嘛)
这个时候estimatedHeightForRowAtIndexPath这货就该出场了,为什么呢?因为有了它和约束就不需要再去手动指定高度了啊(给cell中控件赋值完成的时候也就是其高度确定了的时候,如果heightForRow方法走之前能够确定这个cell的高度,那它的存在也就没有任何意义了,当然这里一定要在cellForRow这个方法中对控件赋值,这对于习惯在willDisplayCell中赋值的童鞋来说是个悲剧,不信你可以试试)~后知后觉了嘛?


运用这个方法省区高度计算最为核心的核心是:cell的top和bottom和其中控件之间的约束正确无误,否则会出现什么意想不到的问题我就不知道了~


内容就上面这些了,不知道我有没有讲清楚,也不知道你有没有心领神会和恍然大悟。有不理解的地方和讲得不对的地方,欢迎下方留言讨论。

时间已近凌晨两点,想想今天(周六)还要加班,赶紧去睡了,泪流满面的时间都没有~

demo地址:https://github.com/NSSONGMENG/TableDemo

你可能感兴趣的:(iOS)