【IT168 技术文档】
图形世界的两个视图
使用Quartz和OpenGL绘图
到目前为止,本文中的所有应用程序都是通过UIKit框架中的视图和控件来构造的。借助这些常备组件,我们可以执行许多操作,并且可以构造各式各样的应用程序界面。但是,如果不能高瞻远瞩,某些应用程序会无法完全实现。例如,有时应用程序需要能够进行自定义绘图。幸而,我们可以依靠两个不同的库来满足我们的绘图需要。一个库是Quartz 2D,它是Core Graphics框架的一部分;另一个库是OpenGL ES,它是跨平台的图形库。OpenGL ES是跨平台图形库OpenGL的简化版。OpenGL ES是OpenGL的一个子集,OpenGL ES是专门为iPhone之类的嵌入式系统(因此缩写为字母“ES”)设计的。本章将介绍这两个功能强大的图形环境。我们将在这两种环境中构建示例应用程序,并尝试了解什么时候使用哪个环境。
图形世界的两个视图
尽管Quartz和OpenGL有许多共性,但它们之间存在明显差别。Quartz是一组函数、数据类型以及对象,专门设计用于直接在内存中对视图或图像进行绘制。
Quartz将正在绘制的视图或图像视为一个虚拟的画布,并遵循所谓的绘画者模型。这只是一种奇特的方式,之所以这么说,是因为应用绘图命令的方式很大程度上与将颜料应用于画布的方式相同。如果绘画者将整个画布涂为红色,然后将画布的下半部分涂为蓝色,那么画布将变为一半红色、一半蓝色或紫色。如果颜料是不透明的,应该为蓝色,如果颜料是半透明的,应该为紫色。
Quartz的虚拟画布采用相同的工作方式。如果将整个视图涂为红色,然后将视图下半部分涂为蓝色,你将拥有一个一半红色、一半蓝色或紫色的视图,这取决于第二个绘图操作是完全不透明的还是部分透明的。每个绘图操作都将被应用于画布,并且处于之前所有绘图操作之上。
另一方面,OpenGL ES以状态机的形式实现。这个概念可能有点不好理解,因为不能将其归结为一个简单的比喻,如在虚拟画布上绘画。OpenGL ES不允许执行直接影响视图、窗口或图像的操作,它维护一个虚拟的三维世界。当向这个世界中添加对象时,OpenGL会跟踪所有对象的状态。虽然 OpenGL ES没有提供虚拟画布,但是却提供了一个进入其世界的虚拟窗口。可以向该世界中添加对象并定义虚拟窗口相对于该世界的位置。然后,OpenGL根据配置方式以及各种对象彼此相对的位置绘制视图,并通过该窗口呈现给用户。这个概念有点儿抽象,因此如果你感到困惑,也不必担心。本章稍后将通过示例详细说明这个概念。
Quartz相对比较容易使用。它提供了各种直线、形状以及图像绘制函数。尽管易于使用,但Quartz 2D仅限于二维绘图。尽管许多Quartz函数会在绘图时利用硬件加速,但无法保证在Quartz中执行的任何操作都得到了加速。
尽管OpenGL非常复杂,并且概念上也比较难理解,但是它的强大性是毫无疑问的。它同时提供了二维和三维绘图工具。它经过专门设计,目的是为了充分利用硬件加速。由于它可以跟踪虚拟世界的状态,因此还非常适合用于编写游戏和其他复杂的、图形密集的程序。
下一个应用程序是一个简单的绘图程序。我们将分别使用Quartz 2D和OpenGL ES来构建该应用程序,因此你会真正感受到它们之间的差别。该应用程序的特点是顶部和底部各有一个工具栏,每个工具栏都有一个分段控件。顶部的控件用于更改图形颜色,底部的控件用于更改要绘制的形状。当用户触击和拖动对象时,程序将用所选颜色绘制所选形状。为了最大程度地降低应用程序的复杂性,一次只绘制一种形状。
Quart绘图方法
使用Quartz绘制图形时,通常会向绘制图形的视图中添加绘图代码。例如,可能会创建UIView的子类,并向该类的drawRect:方法中添加 Quartz函数调用。drawRect:方法是UIView类定义的一部分,并且每次需要重绘视图时都会调用该方法。如果在drawRect:中插入 Quartz代码,则会先调用该代码,然后重绘视图。
Quartz 2D的图形上下文
在Quartz 2D中,和在其他Core Graphics中一样,绘图是在图形上下文中进行的,通常,只称为上下文。每个视图都有相关联的上下文。要在某个视图中绘图时,你将检索当前上下文,使用此上下文进行各种Quartz图形调用,并且让此上下文负责将图形呈现到视图上。
下面这行代码将检索当前上下文:
定义图形上下文之后,可以将该上下文传递给各种Core Graphics函数来进行绘图。例如,以下代码将在上下文中绘制一条2像素宽的直线:
上下文具有一种与绘制直线关联的不可见的“画笔”。调用CGContextMoveToPoint()时,会将这个不可见的画笔移动到新位置,而不是实际绘制任何内容。这表示我们指定要绘制的直线从位置(100, 100)处开始。下一个函数实际上绘制了一条从当前画笔位置到指定位置(该位置将成为新的画笔位置)的直线。在 Core Graphics中绘图时,我们没有绘制任何实际可见内容。我们创建了形状、直线或某些其他对象,但它们不包含颜色或者任何使其可见的内容。就像用不可见的墨水在书写一样。在执行某些操作使其可见之前,我们看不到直线。因此,下一步是告知Quartz使用CGContextStrokePath()绘制直线。该函数将使用之前我们设置的线宽和笔划颜色对此直线进行涂色并使其可见。
坐标系
在上面的代码块中,我们将一对浮点数作为参数传递给CGContextMoveToPoint()和 CGContextLineToPoint()。这些浮点数表示在Core Graphics坐标系中的位置。此坐标系中的位置由其x和y坐标表示,我们通常用(x, y)来表示。上下文左上角为(0, 0)。向下移动时,y增加。向右移动时,x增加。65
在最后一个代码片段中,我们绘制了一条从(100, 100)到(200, 200)的对角线,绘制的直线类似于图所示的直线。
在iPhone绘图时需经常使用的一个概念就是坐标系,它借鉴了许多图形库的绘图机制以及传统的几何学。例如,在OpenGL ES中,(0, 0)位于左下角,当y坐标增加时,你将移向上下文或视图的顶部,如图所示。使用OpenGL时,必须将位置从视图坐标系转换为OpenGL坐标系。这非常容易,在本章稍后的部分中,你将了解如何使用OpenGL。
若要在坐标系中指定一个点,某些Quartz函数需要使用两个浮点数作为参数。其他Quartz函数要求该点嵌入在CGPoint中,CGPoint是一个包含两个浮点值(即x和y)的struct。若要描述视图或其他对象的大小,Quartz将使用 CGSize。CGSize也是一个拥有两个浮点值(即width和height)的struct。Quartz还声明一个名为CGRect的数据类型,它用于在坐标系中定义矩形。CGRect包含两个元素,一个是名为origin的CGPoint,它确定矩形的左上角,另一个是名为size的 CGSize,它确定矩形的宽度(width)和高度(height)。
指定颜色
颜色是绘图的一个重要因素,因此理解颜色在iPhone上的运行原理是非常重要的。UIKit为此提供了一个 Objective-C类:UIColor。你不能在Core Graphic调用中直接使用UIColor对象,但可以像我们之前在以下代码片段中所做的一样,使用它的CGColor属性从UIColor实例中检索 CGColor引用(Core Graphic函数要求这样做):
我们使用redColor便利方法创建了一个UIColor实例,然后检索它的CGColor属性,并将该属性传递给函数。
在视图坐标系中绘制一条直线
在许多图形库(包括OpenGL)中,从(100,
100)到(200, 200)绘制一条直线应该与此类
似,而不是与直线类似
1. iPhone显示的颜色理论
绘制形状:多边形、直线和曲线
Quartz 2D提供了许多函数,这些函数简化了复杂形状创建。若要绘制一个矩形或一个多边形,实际上你不必计算角度,绘制直线或者根本不必进行任何数学计算。你只需调用一个Quartz函数即可实现该操作。例如,绘制椭圆形的方法是,定义它所适合的矩形并且让Core Graphics执行以下任务:
对于矩形也是类似的方法。此外,还有许多方法用于创建更为复杂的形状(如弧形和Bezier路径)。若要了解有关Quartz中弧形和Bezier路径的详细信息,请查看http://developer.apple.com/ documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_intro /chapter_1_section_1.html上的iPhone Dev Center中或Xcode联机文档中的Quartz 2D Programming Guide(Quartz 2D编程指南)。
Quartz 2D工具示例:模式、梯度、虚线模式
Quartz 2D不像OpenGL那么昂贵,却提供了许多吸引人的工具,尽管这些工具中的许多工具不在本书的讨论范围之内,但你应该知道它们的存在。例如,Quart 2D支持用梯度填充多边形,而不只是用纯色,并且不仅仅支持实线,而且还支持虚线模式。浏览图12?5中截取自苹果公司QuartzDemo示例代码的屏幕截图,了解Quartz 2D的实际操作示例。
现在你已经基本了解了Quartz 2D的工作原理以及它的功能,让我们尝试使用它吧。