方案一:直接法(面向对象)
直接法,就是把数据布局到Cell上,然后拿到Cell最底部控件的MaxY值。
第一步:创建Cell并正确设置约束,使文字区域高度能够根据文字内容多少自动调整
添加好约束
第二步:再给这个Cell添加点别的东东,就叫这个东东BottomCub了。为Cub添加好约束。
随便添加点什么
第三步:为这个Cell写一个返回Cell高度 - 也就是BottomCub最大Y值的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
第四步:在代理方法中设置Cell高度
*注意:计算Cell高度的过程,一定不要放在heightForRow代理方法中!这一点在后文中将会有所提及。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
效果
动态设定Cell高度结果
方案二:自己算(面向过程)
通常情况下,Cell之所以不等高,是因为Cell内部文字区域的高度会根据文字数量动态变化,图片区域的高度会根据图片数量而自动变化。也就是说,只要知道文字区域的高度、图片区域的高度,就可以硬生生计算出Cell的高度了。
注意注意注意:如果产品有可能会要求调整行距,切不可用此方法计算!
替代可选方案:
1 |
|
(注于:2016.1.28)
- 第一步:硬生生的将每个Cell的高度算出来,并保存在一个数组中
- 第二步:heightForRow方法中返回相应的CellHeight
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
|
效果
- 就不给效果图了哦,和上一张是一样一样的~
方案三:利用iOS 8新特性
其实,iOS8已经提供了直接通过XIB让Cell高度自适应的方法了,只要简单拖拖线,根本木有必要计算Cell高度,就可以搞定不等高Cell
第一步:设置tableView的估算Cell高度&rowHeight值为自动计算模式
1 2 3 4 5 6 |
|
第二步:为Cell中最下面的View设置约束 - 除了要定高、定宽、左上角粘着Label外,还要设置bottom距contentView的bottom间距为固定值,如0
bottomCub约束的添加方式
第三步:一定要注意 - 不能实现heightForRow代理方法!!!不能实现heightForRow代理方法!!!不能实现heightForRow代理方法!!!重要的事情说三遍...
iOS8新特性实现Cell高度的自适应
效果:一样杠杠滴~
课题二:在哪计算Cell高度
方案一:在heightForRow代理方法中计算
- 示例代码:见课题一方案一
- 说明:在这里进行计算是非常糟糕的选择,因为系统调用heightForRow方法非常频繁 感兴趣的小伙伴可以打印测试下...在这里进行计算,意味着系统每调用一次heightForRow方法,就会执行一次高度计算...好可怕有木有?
方案二:在请求到数据后马上计算
- 示例代码:见课题一方案二
- 说明:在这里进行计算相对于方案一来说进步了很多,在这里计算是不错的选择哦!
方案三:在cellForRow代理方法中算
- 说明:其实,要隆重介绍的是方案三~
- 思路:
1.既然想知道Cell的高度,那么一定是Cell自己最懂自己有多高啦(面向对象的思维)。
2.那么,在哪里能拿到Cell和Cell的高度呢? - 当然是CellForRow代理方法中啦!
3.但是,在CellForRow中拿到Cell高度后,如何传递给heightForRow代理方法呢? - 可以将Cell高度保存在一个数组中,或者保存在Cell对应的Model中~
4.但是,我们知道系统对tableView代理方法的调用顺序,是先调取heightForRow再调取cellForRow的呀,这意味着,我们在cellForRow方法中拿到cell高度之前,就需要设置heightForRow...怎么办?
a.解决方案:实现estimatedHeightForRow代理方法!
b.实现这个代理方法后,系统会先调取cellForRow,再调取heightForRow,而且实现这个代理方法之后,腰不酸了,腿不疼了,一口气上五楼也不费劲了~
- 示例代码:可以参考下我之前的文章哦!传送门 - iOS项目实例:QQ聊天界面UI搭建
- 注意:如果实现了estimatedHeightForRow代理方法,可能会造成tableView的ContentSize值不正确哦!所以,该方法请选择使用...
结论
- 处理不等高TableViewCell,优先使用iOS8新特性(课题一方案三)
- 不能使用iOS8新特性的情况下,优先选择课题一方案一+课题二方案三组合
- 不能用上面两种,优先选择使用课题一方案一+课题二方案二组合~
补充
tableView的contentSize计算机制
实验方案
自定义一个tableView的子类,重写setContentSize方法,在该方法中打印contentSizeHeight,观察总结。
分两组:第一组实现estimatedHeightForRow方法,第二组不实现。
- 第一组:section = 1 rowNumber = 5 | 估算行高10 | 实际行高100
- 第二组:section = 1 rowNumber = 5 | 未实现估算行高 | 实际行高100
实验结果
第一组
实验一 - 1组5行|估算行高10|实际行高100|计算contentSize.gif
第二组
实验二 - 1组5行|不估算|实际行高100|计算contentSize.gif
实验结论
- viewDidAppear方法中拿到的contentSize才是准确的contentSize
- contentSize至少会设置3次,如果估算行高与实际行高不符,会再次设置contentSize
未解之谜
- 通过打印我们可以看到,获取cell之前,诡异地对heighForRow方法遍历了三次...为什么是三次?
- 为什么最少设置3次contentSize,不能只设置1次吗?
- 能否把返回Cell的方法和heightForRow方法合并成一个代理方法?