[关闭]
@qidiandasheng 2016-09-17T15:21:56.000000Z 字数 3455 阅读 4883

iOS界面渲染流程

iOS界面开发


概念

UIView 和 CALayer 的区别

下面两张图表示UIViewCALayer所属的框架和继承体系

详解CALayer 和 UIView的区别和联系这篇文章中有对这两个概念的一个详细理解。

我这里简单概括一下主旨:

UIView是继承自UIResponder的,所以说UIView是可以响应事件的,而CALayer是不能的。
也就是说UIView负责处理用户交互,负责绘制内容的则是它持有的那个CALayer,我们访问和设置UIView的这些负责显示的属性实际上访问和设置的都是这个CALayer对应的属性,UIView只是将这些操作封装起来了而已。
一个UIView只有一个相关联的CALayer(自动创建),同时它也可以支持添加无数多个子CALayer([View.layer addSublayer:layer];),每个CALayer显示一种东西,增强UIView的展现能力。

用途

使用UIView(视图)的好处在于,你能在使用所有CALayer底层特性的同时,也可以使用UIView的高级API(比如自动排版,布局和事件处理)。

而使用CALayer(图层)的情况主要有:
1:开发同时可以在Mac OS上运行的跨平台应用。
2:使用多种CALayer的子类,并且不想创建额外的UIView去包封装它们所有
3:做一些对性能特别挑剔的工作,比如对UIView一些可忽略不计的操作都会引起显著的不同。

所以说CALayerUIView更轻量级,如果不需要一些用户交互的话可以直接使用CALayer绘制,这样对于性能有一定的优化。而UIView当然使用起来更方便。


UIBezierPath 和 CoreGraphics

我们上文提到,CALayer是负责绘制内容管理的一个类,而真正的绘制部分是由CoreGraphics Framework框架来处理的。CoreGraphics中包括下图所示的各种类来处理绘制,比如path的绘图工作(如,CGPath)、变形操作(如,CGAffineTransform)、颜色管理(如,CGColor)、离屏渲染(如,CGBitmapContextCreateImage)、渲染模式(patterns)、渐变(gradients)、阴影效果、图形数据管理、图形创建、蒙版以及PDF文档的创建、显示和解析等等。

UIBezierPath继承自NSObject,是UIKit下关于CoreGraphics中的路径绘制部分CGPath的封装。
使用UIBezierPath可以创建基于矢量的路径,如果是基于矢量形状的路径,都用直线和曲线去创建。我们使用直线段去创建矩形和多边形,使用曲线去创建圆弧(arc)、圆或者其他复杂的曲线形状。


界面渲染的整体流程

关于整个界面渲染的流程这篇文章中有较好的描述。

  • UIKit Framework它主要提供了:界面呈现能力、事件响应能力、驱动RunLoop运行和与系统内核通信的数据。简单来说就是:主要负责界面展示、事件响应以及是RunLoop的需求方。UIView当然是属于UIKit Framework。

  • QuartzCore Framework 与 CoreAnimation它提供了图形处理和视频图像处理的能力。简单来说就是:QuartzCore Framework负责把图形图像最终显示到屏幕上,这里我觉得应该是特指CoreAnimation。不要从字面上去理解CoreAnimation的职责,因为它的核心工作不单是负责动画的创建和执行,它还负责把我们用代码构建的界面显示到屏幕上,实际上是CoreAnimation通过OpenGLES做的。CALayer是属于QuarzCore Framework下的CoreAnimation。

  • CoreGraphics Framework一个基于C库函数的高级绘画引擎,它提供了非常强大的轻量级2D渲染能力。可以使用CoreGraphics处理基于path的绘图工作(如,CGPath)、变形操作(如,CGAffineTransform)、颜色管理(如,CGColor)、离屏渲染(如,CGBitmapContextCreateImage)、渲染模式(patterns)、渐变(gradients)、阴影效果、图形数据管理、图形创建、蒙版以及PDF文档的创建、显示和解析。 千万别和QuartzCore混淆,CoreGraphics负责创建显示到屏幕上的数据模型,QuartzCore(CoreAnimation –> OpenGLES)负责把CoreGraphics创建的数据模型真正显示到屏幕上。 CG打头的类都是属于CoreGraphics Framework

  • 以上三者的关系 三者的关系是通过界面展示以及动画的创建、执行关联起来的,所以它们之间是协作而不是从属的关系。

整个绘制流程主要就是表现在几个框架之间的协作关系,UIKit FrameworkQuartzCore Framework(CoreAnimation)CoreGraphics Framework。整个协作流程如下图所示:

下面按照步骤来讲解:

1:触发界面渲染的情况

1.1 通过在loadView过程中debug子view的drawRect:方法得知:RunLoop处于kCFRunLoopBeforeWaiting状态时会回调CoreAnimation中监听kCFRunLoopBeforeWaiting状态的RunLoopObserver,从而通过RunLoopObserver来进一步调用CoreAnimation内部的CA::Transaction::commit() ();方法,进而一步一步地调用到drawRect方法。

1.2 通过在VC里给一个按钮添加点击事件,并在事件对应的selector中修改子view的背景色,debug子view的drawRect:方法得知:RunLoop被iOS系统传递来的点击事件唤醒并由source1处理(__IOHIDEventSystemClientQueueCallback),并且在下一个runloop里由source0转发给UIApplication(_UIApplicationHandleEventQueue),从而能过source0里的事件队列来调用CoreAnimation内部的CA::Transaction::commit() ();方法,进而一步一步的调用drawRect方法。

上面两种情况都是触发CoreAnimation的CA::Transaction::commit() ();方法来达到触发CALayer/UIView的渲染,所以这个CA::Transaction机制很关键。

2:其实这一步已经进入到了Quarz Core的内部(Core Animation),即调用CA::Transaction::commit() ();来创建CATrasaction,然后进一步调用-[CALayer drawInContext:] ()

3:回调CALayerDelegate(UIView),问UIView没有需要画的内容,即回调到drawRect:方法。

4:在drawRect:方法里可以通过CoreGraphics函数或UIKit中对CoreGraphics封装的方法(如 UIBezierPath)进行画图操作,这些画图的操作内容都是以Off-Screen离屏(广义的离屏,因为没有在GPU中进行)方式进行画图。另,注意图中虚线部分的3|4步骤的情况:因为CALayer可以单独存在进行界面渲染,所以CALayer也可以直接与CoreGraphics产生联系。

5:无论是有UIView参与的或是直接采用CALayer渲染的操作都会体现在CALayer上(在没有CoreGraphics参与的情况下,UIView或CALayer本身也有一些在业务层面需要显示的内容,所以这里说的“体现在CALayer上”,是泛指UIViewr的子视图或CALaye的子图层以及CoreGraphics参与的内容)。

6:CoreAnimation(CALayer)把它的内容转成位图(纹理),然后通过OpenGLES把位图内容传送到GPU的帧缓冲区。

7:等到由iOS显示屏时钟信号驱动的VSync信号来临时,则把GPU帧缓冲区里的内容显示到iOS显示屏上。

参考

详解 CALayer 和 UIView 的区别和联系

界面渲染的整体流程

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注