作为一个android开发移民,在知晓UITableView可能会计算每一个cell的高度时,心里面还是惊了一下。Android的开发文档中,不会有关于计算高度这方面的内容,数据的多少和排版决定高度数值的大小不假,但去“感知”自己的高度难道不是ui组件分内的事儿吗?
可惜这种疑问并没有支撑多久,因为大脑的另一侧已经出现android自适应高度时各种坑和bug,比如在ScrollView当中创建ListView,会发现设置成为自适应高度、多行数据的ListView变成细细一杠,让每一个新手开发大脑回旋“What the fu*k”,用手指拨动它还会上下滑动,像极了LED。至少就动态计算列表高度这一点上,ios和android都没长出什么甜果子。
好了,我只需要知道,一个展示大量列表数据的滑动组件想知道自己的高度,就得计算各个子view的高度,即UITableView需要知道每一个UITableViewCell的高度,这样一来,就算是每个UITableViewCell的高度大小不一,也能完美显示。
那么如何计算每一个UITableViewCell的高度呢?很简单,分两步:
- 用systemLayoutSizeFittingSize:UILayoutFittingCompressedSize获取高度。
- 在heightForRowAtIndexPath当中返回这个高度。
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(cell != nil) {
let size: CGSize = (cell?.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize))!
return (size.height + 1)
}
return 0
}
需要解释的地方在于这个“return (size.height+1)”,为什么要加1?因为这里获取的size是cell当中contentView的size,cell作为老子肯定要比儿子高一头啦,不然怎么管得住儿子?
Cell = ContentView(size.height) + Separator(1px)
利用systemLayoutSizeFittingSize获取cell中contentView的size还有一个前提,就是contentView需要设定constraints,所以实际上这是一个与Auto Layout配套的高度获取方式。
为每个cell计算高度再相加会得到整个UITableView的高度,问题也在于每个cell的计算过程会耗费时间,有大量cell的时候会使得整个ui展示的效率不高,怎么办呢?
这里有一个聪明的概念上的划分,就是“能够被用户看见的cell”和“用户还没有看见的cell”。这里可能有上千行数据,作为系统而言,它计算了每个cell的高度,但是手机屏幕高度有限,只看得到几个cell,这种大量的计算不是很浪费么?就好比我是一家生意红火餐馆,能坐200桌客人,吃饭高峰期我们家客满了,还会在门外等50桌客人,我有必要为这等待的50桌客人备好菜么?我只需要知道等待的这50桌人大概会吃多少菜,保证厨房中的原料足够就可以了。UITableView也有这么一个功能,给还没有看见的cell一个估计的高度,这样既能知道自己的高度大概是多少,又不造成浪费,提高效率。
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 78
}