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来执行,因为这个硬件就是用来做混合操作的(当然不只是混合)。
不要在这里去执行数据绑定,因为目前在屏幕上还没有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来执行,因为这个硬件就是用来做混合操作的(当然不只是混合)。
相关文章推荐
- ValueAnimator
- iOS UIScrollView 的基本用法
- ios中uilabel换行
- RabbitMQ的work queue(1)
- leetcode longest consecutive sequence
- How do you build a database?
- HDU 2604 Queuing(矩阵快速幂)
- Plugin-X Integration Guide for Android
- poj2299Ultra-QuickSort(线段树区间求和单点修改)
- UITableView 的一些冷知识点
- UI文件操作
- PAT-A-1051 Pop Sequence 【栈】
- php之文件载入include, include_once,require,require_once
- Executing Raw SQL Queries using Entity Framework
- 四、安卓UI学习(2)
- 【转】探秘Java中的String、StringBuilder以及StringBuffer
- 一天一排序之“快速排序(quic_sort)”
- POJ 1679 The Unique MST 次小生成树
- 设置UITabBarController的图片问题
- Android常用UI之AlertDialog