“UITableView完美平滑滚动”阅读笔记
来源:互联网 发布:盐城大数据产业园 编辑:程序博客网 时间:2024/05/18 03:56
一、通过内置工具实现浅层次优化
使用内置工具优化 UITableViews 的正确方式:
- 重用 cell对象:对于特定的 cell类型,你应该只初始化一次
- 不要在cellForRowAtIndexPath: 方法绑定数据,因为这时 cell还没显示,而是使用UITableViews 的委托方法tableView:willDisplayCell:forRowAtIndexPath:。
- 进一步计算 cell的高度要迅速。虽然这是工程师的日常事务,但是要想平滑滚动复杂的 cell,你要多点耐心。
下面对上面三点稍作说明:
1、重用 cell/header/footer的单个实例是优化UITableView最显著的方式,正确的做法是,你应该持有唯一的 cell/header/footer 类,且只初始化了一次,并返回给UITableView 来重用该对象。由于为每个cell都执行一次,所以这些代理函数必须迅速执行,否则会出现卡顿现象。
2、UITableView的 tableView: heightForRowAtIndexPath:委托方法会为每个 cell(即使它不显示)调用一次,所以你应当非常迅速返回当前 cell的高度,否则会出现卡顿现象。
从 iOS8 开始,我们可以使用自动高度计算,而无需实现上面提到的UITableViews 的委托方法。要做到这一点,你可以使用AutoLayout 工具,并把行高设置为 UITableViewAutomaticDimension。更多的详细信息可以在StackOverflow网站上找到,上面有很好的解释。尽管可以使用这些工具,但我还是强烈建议你不要这么做。另外,我建议不要使用更复杂的数学运算来确定 cell的高度,而尽可能仅仅使用加、减、乘、除。AutoLayout 难道真如我所那么慢?也许你会感到惊讶,但这的确是事实。如果你的应用运行在所有的生命周期长的真实设备,想看到完美的平滑滚动,那么结果会是慢得令人难以置信的。而且你拥有越多的子视图,你的AutoLayout 就运行得越慢。
AutoLayout 相对低性能的原因是在 Cassowary 布局引擎下处理的。你需要要处理的的子视图布局约束越多,你花费在返回 cell给 UITableViews 的时间就越多。
二、平衡CPU和GPU,实现进一步优化
上面提及的几点还不足以实现真正的平滑滚动,尤其当你需要实现复杂的 cell,有着许多梯度渐变、视图、交互元素、装饰元素等更多的内容时,其平滑滚动效果更差。你给UITableViewCell 添加的视图越多,其滚动时的 FPS下降的幅度就越大,因为cell越复杂则混合渲染的视图越多,GPU会满载,造成渲染时间被拉长。
让我们把注意力转移到 UIView 的 “opaque”的属性上,绘图系统根据opaque属性确定UIView 是否为透明,如果不透明,则绘图系统在呈现该视图时会做一些优化并提高性能。
GPU(图形处理器),它是显卡的“心脏”,与CPU类似,只不过GPU是专为执行复杂的数学和几何计算而设计的,这些计算是图形渲染所必需的。用途是将计算机系统所需要的显示信息进行转换,控制显示器的正确显示,是连接显示器和个人电脑主板的重要元件。显卡作为电脑主机里的一个重要组成部分,承担输出显示图形的任务,对于从事专业图形设计的人来说显卡非常重要。iOS系统对图形的各种特效处理基本上正好都是基于GPU硬件进行加速的,它可以不用完全借助CPU或者程序本身,而是通过GPU进行渲染以达到更流畅的操控表现,但是过多的混合渲染会使的gpu处于满载状态而造成性能下降!所以tableview中提高性能的方法是减少混合渲染,确认哪些视图进行混合渲染了的方法是:在 iOS 模拟器运行你的应用,点击“Debug”菜单,然后选择“Color Blended Layers”选项。这时 iOS模拟器会将所有区域的显示划分成两种颜色:绿色和红色,绿色区域是没有混合渲染的,红色区域是经过有混合渲染的。
每次遇到这样的情况,你都应当仔细研究,并在不同的情况下,使用不同的方式来避免混合渲染,我在这种情况下,将背景色 设置不透明就已经实现目标了。
但有时候我们会遇到更复杂的事情。看这里:我们有一个梯度渐变,但混合是不存在的。如果你想使用CAGradientLayer 来实现这个效果,你会失望的,因为在 iPhone 6其 FPS 会下降到 25~30,并且无法达到快速滚动。
它毕竟是会发生的,因为我们已经将两个不同图层的内容混合了,分别是UILabel 的 CATextLayer 和 CAGradientLayer。
当正确使用 CPU 和 GPU资源,它们是负载均衡的,FPS保持约为 60。如下所示:
当设备需要显示执行大量的混合操作时问题就会出现,GPU将会满载,但 CPU 却会保持低负荷运行。
通过本文的所有建议,你将能够让你的应用即使在这种情况下都可以达到 60 FPS,尽管其过程有些难度。解决方法就是:用 CPU来渲染!去载 GPU,让它只在必须用 GPU的地方执行混合渲染。例如,由CALayers 执行动画的地方。
我们可以通过在UIView 的drawRect: 方法中使用CoreGraphics 操作,如:
这些代码就很好吗?即使是我,也会说no。另外这种方式是撤销所有在UIView 上的缓存优化(在任何情况下,它们都是不必要的)。但正是这种做法将禁用一些混合操作,不加载 GPU并能让 UITableViews 更流畅。
但要注意:使用这种方式增加渲染性能不是因为 CPU比 GPU 快!而是因为 CPU 在多数情况下都不会 100%满载,这种方式能让我们通过负载 CPU来实现在一些渲染任务中去载 GPU。
优化混合操作的关键是平衡 CPU和 GPU 的负载。
简单总结一下优化在 UITableViews 中绘制数据的操作:
- 减少 iOS没必要的混合渲染区域:通过 iOS模拟器和 Instruments 工具对应用进行检查,不使用透明背景;如果可以的话,不渲染梯度渐变,其效果会更好。
- 优化代码,实现 CPU和 GPU 负载均衡。你应清晰了解哪一部分的渲染必须通过 GPU来完成,哪一部分的渲染可以通过 CPU来保持均衡。
- 根据不同类型 cell写不同的代码。
三、通过减少子像素渲染,实现进一步优化
实际上,每个物理像素是通过红、绿、蓝三种颜色子像素组成的,这就造成了每个像素并不是原子单元的,尽管在应用中看起来是原子单元的。直到搭配视网膜屏的 iPhone 4 出现,物理像素可以被描述为整形坐标。因为视网膜显示屏是多倍于屏幕点,而不是 Cocoa Touch 环境中的像素,而且他们可以为浮点数。
理想状况下,屏幕点总是被处理成物理像素的整数坐标,但在现实生活中,它可能是浮点数值,例如,直线可能开始于横坐标的 0.25处。并从这时,iOS 将对子像素进行着色。当这种技术运用于特定类型的内容(如文本)确实比较合理。但如果我们只是绘制设计的平滑直线时就没必要使用这种技术。如果你的所有的平滑直线都进行子像素渲染(这将是不可见的,因为你的直线只是设计成平滑的),那么你会让 iOS 做无用功,同时也降低了 FPS。
如何获得与不必要的子像素抗锯齿的问题?最经常发生的情况是在需要代码计算的视图中,其坐标系数值变成了浮点数值或者使用不适合的图片素材,图片尺寸不对齐屏幕的物理像素(例如,你有一张 60×61而不是 60×60 的图片给视网膜屏显示)
就如前面内容提到的,在减少一些东西前,我们应去找到它。在 iOS模拟器运行你的应用,并点选“Debug”菜单的“Color Misaligned Images”选项。
这次,模拟器上有两大高亮的区域:紫红色区域执行了子像素渲染,黄色区域渲染的图片尺寸没有对齐到它们所在的区域。
。
如何在你的代码中找到发生问题的地方?我总是使用部分自定义绘制进行手工布局的,所以对我来说没问题。如果你是使用Interface Builder,那么我只能同情你了。
一般情况下,解决这个问题只需要简单使用下ceilf、floorf和 CGRectIntegral 来凑整你的坐标系即可。
通过探索的结果,我有以下几点建议:
- 凑整所有像素相关的数据:UIView的点坐标、宽高和其他数据。
- 追踪你的图像资源:图片必须是像素完美的,否则当它们在视网膜屏上渲染时,它会做一些无必要的抗锯齿处理。
- 定期检查你的环境和上述的问题,因为它可以很快修正。
四、通过“异步加载UI”实现进一步优化
每个中等以上级别的应用都有必要使用带自定义多媒体内容的 cell,如:文本、图片、动画,甚至有时是视频。而所有这些东西都被修饰:头像是圆的、文字带话题标签、用户名等。我们注意到,对于需要尽快返回的 cell,在这点上我们有些麻烦:clipsToBounds 慢,图片从网络加载,字符串要关联话题标签等其他一些麻烦。
优化似乎是这样的:你应执行这些操作,但如果你执行在主线程,那么它不会让你快速返回 cell。后台加载图片并处理圆角,然后将处理过的图片赋值给UIImageView。一次显示所有文本,但在后台关联话题标签,然后刷新带样式的文本。
具体的操作取决于你的 cell 的具体内容,但主要的想法是让它在非主线程运行大量的操作。这些操作不仅是网络相关代码并且使用Instruments 工具来找出所在需要在代码运行的操作。
有时候,我们即使用尽了上面所有的技术都无补于事。GPU仍然不奏效(iPhone 4 + iOS 7),cell中有大量内容,我们将要通过CALayers 来实现动画,因为它真的很难通过drawRect: 方法实现效果。在这种情况下,我们应该在后台渲染其他的一切。
设置 CALayers 为异步显示模式(即使它们简单的文本或图片),也将帮助你提高 FPS,即设置CALayers 的 drawsAsynchronously为 YES。
在 iOS 模拟器运行应用,选择“Debug”菜单的“Color Offscreen-Rendered”选项。现在所有在后台渲染的区域会以黄色突出显示。
为了找到CALayers 的瓶颈并进一步缩小它,你可以使用 XCode Instruments的 Time Profiler工具。
下面是实现异步 UI 的操作列表:
- 找到那个不能让你快速返回 cell的渲染瓶颈。
- 将操作移至后台并更新在主线程的显示内容。
- 最后一招是设置CALayers 为异步显示模式(即使它们简单的文本或图片),这将帮助你提高 FPS。
- “UITableView完美平滑滚动”阅读笔记
- UITableView 的完美平滑滚动
- UITableView 的完美平滑滚动
- 平滑滚动
- jquery平滑滚动插件
- 平滑滚动到锚点
- SeekBar平滑滚动修改
- Scroller平滑滚动
- 平滑图片滚动
- Scroller和平滑滚动
- 自定义View-平滑滚动
- 【Android】SeekBar平滑滚动
- 全屏平滑滚动网页
- js 滚动条平滑移动
- jQuery实现页面平滑滚动
- vue平滑滚动到顶部
- javaScript滚动新闻之上下左右平滑滚动
- RecycleView 滚动 平滑滚动到某位置
- 程序员要学会读源代码
- JS立即执行
- 51nod 1031(快速幂)
- Python 文件读写
- Jeff Atwood倾情推荐——程序员必读之书
- “UITableView完美平滑滚动”阅读笔记
- Matlab多线程与多核运算, 以及GPU加速
- Git学习8:Git分支操作
- 所有编程皆为Web编程
- 正则表示式实例1--判断某个数是不是4的幂数
- hiho 60. Permutation Sequence
- AndroidStudio简单快速导入GitHub中的第三方插件
- 成为优秀程序员的方法就是抛开编程?
- ServiceManager如何成为Binder进程通信的守护进程