estimatedRowHeight 与 self sizing cells

estimatedRowHeight

为什么要引入estimatedRowHeight呢?顾名思义就是预估高度。在预估高度之前,与高度相关的属性及方法比较常用的有以下两个:
* rowHeight:这个属性适合用于拥有固定高度的tableview,这种方式比较高效,滚动时没有任何高度计算,可以得到较好的滚动体验。
* tableview:heightForRowAtIndexPath:这种方式适用于tableview需要根据不同的内容展示不同高度的cell,在该方法中计算得出cell高度。但是这种方式的缺点也很明显,即使你有20,000行的cell,系统也会在tableview加载的时候提前获取所有cell的高度。延长了tableview的加载时间。

文档中对estimatedRowHeight的解释是这样的:提供一个非负的预估行高可以提高tableview的加载速度。如果一个tableview中包含可变的行高,当tableview加载数据时,会去计算所有的行高,这个代价是很大的。使用预估高度的话,你就可以将一些计算工作从加载时间推迟到滚动时间。

我们都知道,创建一个UIScrollView,需要设置它的contentSize,才可以正确的显示,tableview也一样,tableview在创建了之后,需要知道即将展示在tableview中展示的数据个数以及每条数据内容决定的cell的高度,这样才能计算得到其contentSize,得到contentSize之后,才能正确得显示。因此,如果你实现了tableview:heightForRowAtIndexPath:的代理方法,tableview会在加载阶段调用所有的cell对应的该方法(设置不止一次地调用),去计算contentSize。如果你在高度计算的代理方法中进行了很复杂的计算,那么你很可能会在页面出现好久,才看到的tableview显示。因此,预估高度的出现,使得加载时不需要去计算所有cell对应的真实高度,而是使用预估高度计算得出一个预估的contentSize,在你滚动tableview的时候,随着cell不断滚入屏幕,cell的高度也被计算出来,这个时候tableview.contentSize再根据不断计算得出的cell的真实高度来进行调整。这么做的高处是,你不需要等好久才看到tableview展示出来了。但是缺点也很明显,你本可以在加载时候将所有cell的高度计算并缓存,这样滚动时就不需要再进行计算,直接取得缓存高度酒可以,但是预估高度的存在,使得在滚动时才会去计算cell高度,滚动体验会受到影响。这个时候,还是不要开启预估高度的好。另外,tableview在不断调整自己的contentSize的过程中,右侧的indicator会出现突然变化或者跳跃的现象。

下面一组数据反应了iOS不同系统版本中关于预估高度作出的改变:(见ppt中的数据)

由此得出下面几个结论:
* 不使用预估高度时初始计算高度计算次数很高,远大于数据的数量
* 使用预估高度之后初始高度计算次数大大减小,优化了tableview加载的时间
* 除了iOS7之外,8-9在继续滚动时依旧会计算cell高度

iOS8中苹果推荐使用动态字体,也就是用于可以在设置中调整字体大小,这样一来,你的cell即使已经加载了数据,高度也是会发生变化的,因此在iOS8之后,即使tableviewcell高度已经计算过,只要你不停滚动,计算也不会停止。

self-sizing cells

假设我们正在滚动一个tableview,此时第四行cell即将出现在屏幕上,在这个cell被创建之前,我们所知道的只有它的预估高度,继续滚动,当cell即将出现在屏幕上时,被创建出来,然后系统会去问cell要它的size,如果这个size不同于之前的estimatedRowHeight的值,系统会对tableview.contentSize进行调整,调整之后,cell就会出现在屏幕上了。

因此,self-sizing也就是说让cell自己负责计算自己的高度,那么cell如何决定自己的高度呢?有以下三种方法:

  • Auto Layout
  • Override sizeThatFits()
  • Override preferredLayoutAttributesFittingAttributes()
    值得注意的是,对cell设置约束时,需要把cell的宽高都指定好。如果你的tableview是通过nib或者storyboard创建的,cell会有一个默认高度,这个时候一定不要忘了下面这行代码:
tableview.rowHeight = UITableViewAutomaticDimension;

这也就意味着高度tableview,我没有行高,你需要根据其他的信息得出行高。

UICollectionViewFlowLayoutAutomatic

这是iOS10中为estimatedItemSize新增的一个值。iOS10以前,你会设置你的estimatedItemSize为一个具体的预估大小,在你滚动UICollectionView的过程中,这个预估大小一直被用于未创建的cell,没有变化。在iOS10中,如果你设置了

layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize;

UICollectionView在为你计算cell的预估大小,并且,随着cell不断被加载出来,这个预估大小也会不断调增,逐渐调整为一个最为接近的值,这就为我们解决了有时候不知道设置一个怎样的预估大小的问题。

你可能感兴趣的:(技术博客)