您的位置:首页 > 产品设计 > UI/UE

UITableView的卡顿优化

2016-04-05 22:36 239 查看
在UITableView的dataSource中实现的tableView:cellForRowAtIndexPath:方法,需要为每个cell调用一次,它应该快速执行。所以你需要尽可能快地返回重用cell实例。

不要在这里去执行数据绑定,因为目前在屏幕上还没有cell。为了执行数据绑定,可以在UITableView的delegate方法tableView:willDisplayCell:forRowAtIndexPath:中进行。这个方法在显示cell之前会被调用。

这个方法对于cell定高的UITableView来说没有意义,但如果由于某些原因需要动态高度的cell的话,这个方法可以很容易地让滑动更流畅。

正如我们所知,UITableView是UIScrollView的子类,而UIScrollView的作用是让用户可以与比屏幕实际尺寸更大的区域交互。任何UIScrollView的实例都使用诸如contentSize、contentOffset和其它许多属性来将正确的区域显示给用户。

但是UITableView的问题在哪?正如所解释的一样,UITableView不会同时维护所有cell的实例。相反,它只需要维护显示给用户的那些cell。

那么,UITableView是如何知道它的contentSize呢?它是通过计算所有cell的高度之和来计算contentSize的值。

UITableView的delegate方法tableView:heightForRowAtIndexPath:会为每个cell调用一次,所以你应该非常快地返回高度值。

很多人会犯一个错误,他们会在布局初始化cell实例并绑定数据后去获取它们的高度。如果你想优化滑动的性能,就不应该以这种方式来计算cell的高度,因为这事难以置信的低效,iOS设备标准的60
FPS将会降低到15-20 FPS,滑动会变得很慢。

从iOS 8开始,我们可以在UITableView的delegate中使用自动高度计算,而不需要实现上面提到的方法。为了实现这一功能,你可能会使用AutoLayout,并将rowHeight变量设置为UITableViewAutomaticDimension。可以在StackOverflow中找到更多详细的信息。

尽管可以使用这些方法,但我强烈建议不要使用它们。另外,我也不建议使用复杂的数学计算来获取cell的高度,如果可能,只使用加、减、乘、除就可以。
但如果是AutoLayout呢?它真的跟我所说的一样慢么?你可能会很惊讶,但这是事实。如果你想让你的App在所有设备上都能平滑的滚动,你就会发现这种方法难以置信的慢。你使用的子视图越多,AutoLayout的效率越低。

AutoLayout相对低效的原因是隐藏在底层的命名为”Cassowary“的约束求解系统。如果布局中子视图越多,那么需要求解的约束也越多,进而返回cell给UITableView所花的时间也越多。

使用内建方法优化UITableView的正确方法是:

重用cell实例:对于特殊类型的cell,你应该只有一个实例,而没有更多。

不要在cellForRowAtIndexPath:方法中绑定数据,因为在此时cell还没有显示。可以使用UITableView的delegate中的tableView:willDisplayCell:forRowAtIndexPath:方法。

快速计算cell高度。对于工程师来说这是常规工作,但你将会为优化复杂cell的平滑滑动所付出的耐心而获取回报。

我们需要更深一步

当然,上面提到的这些点不足以实现真正的平滑滚动,特别是当你需要实现一些复杂的cell(如有大量的渐变、视图、交互元素、一些修饰元素等等)时,这变得尤其明显。

这种情况下,UITableView很容易变得缓慢,即便是做了上面所有的事情。UITableViewCell中的视图越多,滑动时FPS越低。但在使用了手动布局和优化了高度计算后,问题就不在布局了,而在渲染了。

让我们把关注点放在UIView的opaque属性上。文档中说它用于辅助绘图系统定义UIView是否透明。如果不透明,则绘图系统在渲染视图时可以做一些优化,以提高性能。

我们需要性能,或者不是?用户可能快速地滑动table,如使用scrollsToTop特性,但他们可能没有最新的iPhone,所以cell必须快速地被渲染。比通常的视图更快。

渲染最慢的操作之一是混合(blending)。混合操作由GPU来执行,因为这个硬件就是用来做混合操作的(当然不只是混合)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: