高质量的图形展示在app的交互界面中扮演非常重要的角色。高质量的图形展示让用户更能喜欢使用它。iOS系统主要提供两种途径去创建高质量的图形:OpenGL或者使用原生Quarts、Core Animation和UIKit。本文会展开讲一下后者。
Quartz是主要的绘制途径,它提供了基于路径绘制、抗锯齿绘制、渐变色、图形绘制、颜色、变形和PDF文档的创建展示和解析能力。UIKit是对Quartz的线条、图片和颜色操作的封装。Core Animation提供了对在动画中修改UIView属性的的支持,同时还可以实现自定义动画。
这个章节会讲述iOS App中的渲染过程,并说明其中用到的绘制原理。可以帮你学习到一些可以让你自己app优化渲染的小技巧。
重要:并非所有UIKit的类都不是线程安全的。请确认在执行绘制的时候处于主线程。
UIKit 图形系统
在iOS中,无论使用哪种技术(OpenGL、Quartz、UIKit或者Core Animation)绘制在UIView或者子类中,都会在屏幕上展示。视图定义自己在屏幕上如何绘制,或者说如何展现自己。系统提供的视图会自动定义自己的展现。自定义视图你必须定义视图如何展现。本章就会讲解通过Quartz、Core Animation和UIKit去绘制自定义图形。
另外,可以离屏绘制位图和PDF图形上下文(译者吐槽:是不是意味着这部分可以不在主线程绘制?)。当你离屏绘制时,因为没有在视图上进行绘制,所以视图的生命周期也对此不起作用。
视图生命周期
UIView的子类包含了最基本的图形绘制模型 -- 根据需要更新绘制自身。UIView类通过批量更新绘制以及在合适的时机更新绘制自身来做到让更新自身绘制变得简单和高效。
当一个视图第一次或者某部分需要更新的时候iOS系统总是会去请求drawRect:方法。
以下是触发视图更新的一些操作:
移动或删除视图
通过将视图的hidden属性设置为NO
滚动消失的视图再次需要出现在屏幕上
视图显式调用setNeedsDisplay或setNeedsDisplayInRect:方法
视图系统都会自动触发重新绘制。对于自定义视图,就必须重写drawRect:方法去执行所有绘制。在方法中通过原生绘制API来绘制本身的形状、文字、图片、渐变或者任何你希望展示的部分。视图第一次展示的时候,iOS系统会传递正方形区域来表示这个视图绘制的区域,为了最大程度优化性能,重绘的时候最好只重绘受影响的部分。
在调用drawRect:方法之后,视图就会把自己标记为已更新,然后等待下一次视图更新被触发。静态自定义视图需要处理因为滚动而出现或者因为其他视图出现而引起的视图变化。(译者吐槽:后半句啥意思?没太懂)
如果想要改变视图的内容,就必须触发视图重绘内容。通过调用setNeedsDisplay或者setNeedsDisplayInRect:方法来触发更新。使用场景例如一秒内多次更新视图,或者根据用户的交互行为在视图中出现新的内容。
重要:不要显式调用drawRect:方法。这个方法应该只留给iOS需要重新绘制的时候留给系统调用。因为在其他时机图形上下文是不存在的,所以也不能对屏幕进行绘制。(图形上下文下一个小节会说明。)
坐标系统及iOS中的绘制
当App需要在iOS系统中绘制图形时,它必须绘制在一个二维坐标系中。这看上去很简单,但在某些绘制情况下需要处理另一种不同的坐标系。
iOS的图形绘制需要依靠图形上下文来完成。理论上说,图形上下文是用来描述在哪里、如何画上,包括颜色绘制、切割绘制区域、线条粗细和样式等信息。
另外,图1-1中展示了每个图形上下文都有一个坐标系。更准确的说,每个图形上下都三个坐标系:
绘制坐标系。绘图上下文通过使用指令绘制的坐标。
视图坐标系。相对于视图的固定坐标系。
设备坐标系。物理屏幕的像素展示坐标。
图1-1 绘制坐标、视图坐标以及硬件坐标关系
译者注:CTM是Quartz中的一个概念,下面会介绍。
iOS的绘图框架为绘制特定的目标(屏幕、位图、PDF内容等)创建图形上下文,这些图形上下文为该目的地建立初始绘图坐标系。这个初始的坐标系被称为默认坐标系,是1比1映射到视图坐标系上的。(译者吐槽:后半句没懂)
每个视图都有一个自己的current transformation matrix(CTM),一个数字举证映射当前绘制坐标系到视图坐标系。