UI卡顿&掉帧的原因
一般页面滑动的帧数在60fps以内时,页面才会流畅,也就是说每一秒内有60次的画面更新,相当于在每隔16.7ms产生一帧画面,在16.7ms内 CPU 和 GPU 要完成一帧画面的绘制与渲染。

-
正常显示:
比如说 CPU 要在一定时间内完成视图的文本的布局、视图的绘制以及图片的解码等工作,最终将位图 (bitmap) 提交给 GPU ,然后 GPU 完成视图的渲染,最终在16.7ms内提交给视频控制器显示在屏幕上。

-
掉帧
如果说 CPU 在16.7ms内占用的时间过多,最终导致 GPU 在16.7ms以后才将图片渲染完提交给视频控制器,就会导致掉帧,UI界面的卡顿
UIView的绘制原理

当调用 UIView 的 方法时并不会立即绘制视图,它会先调用视图所对应的的 layer 的同名方法
方法,相当于在当前视图上打上了个脏标记,然后在当前 runloop 将要结束时调用 CALyer 的
方法,最后才会进入绘制流程当中。
在调用 CALyer 的 方法时,首先会先判断是否响应 layer 的
代理方法,如果不响应则进入系统绘制流程,当响应时,则进入异步绘制入口。
系统绘制流程

- CALayer 会回先创建一个 backing store(CGContextRef) 的上下文,然后会在 drawRect 方法中会在上下文堆栈中拿到 backing store
- 判断是否 CALayer 是否有代理
- 如果没有代理,则调用系统的
方法
- 如果有代理,则会调用 layer.delegate 的
方法,该方法发生自系统内部,最后在合适的时机会调用
方法,该方法默认是什么都不做的
- 最后都会将 backing store (位图)上传至GPU中,最后结束绘制
异步绘制
- [layer.delegate displayerLayer:]
- 代理负责生成对应的bitmap
- 设置该bitmap作为layer.contents属性的值

- 假如说在某个时间调用
方法
- 然后在当前 runloop 将要结束的时候,会由系统调用视图所对应的
方法,如果我们的 delegate 方法实现了
方法,则由系统调用该方法
- 然后会通过子线程的切换,在子线程中实现视图的绘制
- 在子线程中创建位图的上下文(
),然后做UI的绘制工作(
),然后根据绘制的上下文生成一张 CGImage 图片(
)
- 最后回到主队列中,将该 CGImage 图片设置为 CALayer 的 contents
离屏渲染
-
在屏渲染(On-Screen Rendering)
指的是 的渲染操作是在用于当前屏幕显示的缓冲区中进行的
-
离屏渲染(Off-Screen Rendering)
指的是 在当前屏幕缓冲区以外开辟一个
进行渲染操作
-
离屏渲染何时触发
1、设置圆角(同时设置maskToBounds时才会触发)
2、设置视图的图层蒙版
3、设置阴影
4、设置光栅化
-
为何要避免离屏渲染
离屏渲染会导致 GPU 增加额外的开销,会导致在CPU和GPU处理的视图的总时长增加,超过16.7ms,可能会导致视图的卡顿和掉帧
滑动优化方案
-
CPU:
1、对象的创建、调整、销毁
2、预排版(布局计算、文本计算等)
3、预渲染(文本的异步绘制、图片的编解码等)
-
GPU:
1、避免离屏渲染
2、避免视图混合(视图层级太多)
网友评论