UIKit
UIKit
是iOS开发最经常使用的框架,能够经过设置UIKit
组件的布局以及相关属性来绘制界面。
事实上,UIKit
自身并不具有在屏幕成像的能力,其主要负责对用户操做事件的响应(UIView
继承自UIResponder
),事件响应的传递大致是通过逐层的视图树遍历实现的。ios
Core Animation
Core Animation
源自于Layer Kit
,动画只是Core Animation
的冰山一角。 Core Animation
是一个复合引擎,其职责是尽量快地组合屏幕上不一样的可视内容,这些可视内容可被分解成独立的图层(即CALayer),这些图层会被存储在一个叫作图层树的体系之中。从本质上而言,CALayer
是用户所能在屏幕上看见的一切的基础。缓存
Core Graphics
Core Graphics
基于Quartz
高级绘图引擎,主要用于运行时绘制图像。开发者可使用此框架来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像建立和图像遮罩以及PDF文档建立,显示和分析。bash
当开发者须要在运行时建立图像时,可使用Core Graphics
去绘制。与之相对的是运行前建立图像,例如用Photoshop提早作好图片素材直接导入应用。相比之下,咱们更须要Core Graphics
去在运行时实时计算、绘制一系列图像帧来实现动画。app
Core Image
Core Image
与Core Graphics
偏偏相反,Core Graphics
用于在运行时建立图像,而Core Image
用于处理运行前建立的图像。Core Image
框架拥有一系列现成的图像过滤器,能对一寸照的图像进行高效的处理。
大部分状况下,Core Image
会在GPU中完成工做,若是GPU忙,会使用CPU进行处理。框架
OpenGL ES
OpenGL ES
是OpenGL
的子集。在图形渲染原理一文中提到过OpenGL
是一套第三方标准,函数的内部实现由对应的GPU厂商开发实现。OpenGL / OpenGL ES
入门篇,请参考OpenGL/OpenGL ES 入门:图形API以及专业名词解析等系列文章函数
CALayer
事实上是用户所能在屏幕上看见的一切的基础。为何UIKit
中的视图可以呈现可视化内容,就是由于UIKit
中的每个UI视图控件其实内部都有一个关联的CALayer
,即backing layer
。
因为这种一一对应的关系,视图层级有用视图树的树形结构,对应CALayer
层级也拥有图层树的树形结构。oop
其中,视图的职责是建立并管理图层,以确保当子视图在层级关系中添加或被移除时,其关联的图层在图层树中也有相同的操做,即保证视图树和图层树在结构上的一致性。布局
为何iOS要基于UIView和CALayer提供两个平行的层级关系呢?post
其缘由在于要作职责分离,这样也能避免不少重复代码。在iOS和Mac OSX两个平台上,事件和用户交互有不少地方的不一样,基于多点触控的用户界面和基于鼠标键盘的交互有着本质的区别,这就是为何iOS有UIKit
和UIView
,对应Mac OSX有AppKit
和NSView
的缘由。它们在功能上很类似,可是在实现上有着显著的区别。动画
实际上,这里并非两个层级关系,而是四个。每个都扮演着不一样的角色。除了视图树和图层树,还有呈现树和渲染树。
CALayer
那么为何CALayer
能够呈现可视化内容呢?由于CALayer
基本等同于一个纹理。纹理是GPU进行图像渲染的重要依据。
在图形渲染原理中提到纹理本质上就是一张图片,所以CALayer
也包含一个contents
属性指向一块缓存区,称为backing store
,能够存放位图(Bitmap)。iOS中将该缓存区保存的图片称为寄宿图。
图形渲染流水线支持从顶点开始进行绘制(在流水线中,顶点会被处理生成纹理),也支持直接使用纹理(图片)进行渲染。相应地,在实际开发中,绘制界面也有两种方式: 一种是手动绘制;另外一种是使用图片。
对此,iOS中也有两种相应的实现方式:
Contents Image
Contents Image
是指经过CALayer
的contents
属性来配置图片。然而,contents
属性的类型为id
,在这种状况下,能够给contents
属性赋予任何值,app仍能够编译经过。可是在实践中,若是contents
的值不是CGImage
,获得的图层将是空白的。
既然如此,为何要将contents
的属性类型定义为id
而非CGImage
。由于在Mac OS系统中,该属性对CGImage
和NSImage
类型的值都起做用,而在iOS系统中,该属性只对CGImage
起做用。
本质上,contents
属性指向的一块缓存区域,称为backing store
,能够存放bitmap数据。
Custom Drawing
Custom Drawing
是指使用Core Graphics
直接绘制寄宿图。实际开发中,通常经过继承UIView
并实现-drawRect:
方法来自定义绘制。
虽然-drawRect:
是一个UIView
方法,但事实上都是底层的CALayer
完成了重绘工做并保存了产生的图片。 下图所示为drawRect:
绘制定义寄宿图的基本原理
UIView
有一个关联图层,即CALayer
。CALayer
有一个可选的delegate
属性,实现了CALayerDelegate
协议。UIView
做为CALayer
的代理实现了CALayerDelegate
协议。-drawRect:
,CALayer
请求其代理给予一个寄宿图来显示。CALayer
首先会尝试调用-displayLayer:
方法,此时代理能够直接设置contents
属性。- (void)displayLayer:(CALayer *)layer;
复制代码
-displayLayer:
方法,CALayer
则会尝试调用-drawLayer:inContext:
方法。在调用该方法前,CALayer
会建立一个空的寄宿图(尺寸由bounds
和contentScale
决定)和一个Core Graphics
的绘制上下文,为绘制寄宿图作准备,做为ctx
参数传入。- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
复制代码
Core Graphics
绘制生成的寄宿图会存入backing store
。介绍一下Core Animation
流水线的工做原理:
Render Server
进程。
App经过IPC将渲染任务及相关数据提交给Render Server
。Render Server
处理完数据后,再传递至GPU。最后由GPU调用iOS的图像设备进行显示。
Core Animation
流水线的详细过程以下:
Render Server
,即完成了一次commit Transaction
操做。Render Server
主要执行OpenGL、Core Graphics相关程序,并调用GPU。Frame Buffer
、视频控制器等相关部件,将图像显示在屏幕上。对上述步骤进行串联,他们执行所消耗的时间圆圆超过16.67ms,所以为了知足对屏幕的60FPS刷新率的支持,须要将这些步骤进行分解,经过流水线的方式并行执行,以下图:
Commit Transaction
在Core Animation
流水线中,app调用Render Server
前的最后一步Commit Transaction
其实能够细分为4个步骤:
Layout
Display
Prepare
Commit
Layout
Layout
阶段主要进行视图构建,包括:LayoutSubviews
方法的重载,addSubview:
方法填充子视图等。
Display
Display
阶段主要进行视图绘制,这里仅仅是设置成像的图元数据。重载视图的drawRect:
方法能够自定义UIView
的显示,其原理是在drawRect:
方法内部绘制寄宿图,该过程使用GPU和内存。
Prepare
Prepare
阶段属于附加步骤,通常处理图像的解码和转码等操做。
Commit
commit
阶段主要将图层进行打包,并将它们发送至Render Server
。该过程会递归执行,由于图层和视图都是以树形结构存在。
iOS动画的渲染也是基于上述Core Animation
流水线完成的。这里咱们重点关注app与Render Server
的执行流程。
平常开发中,若是不是特别的复杂动画,通常使用UIView
Animation实现,iOS将其处理过程分为以下三部阶段:
animationWithDuration:animations:
方法Layout,Display,Prepare,Commit
等步骤。Render Server
根据Animation逐帧进行渲染。参考博客 iOS图像渲染原理