Lập trình ứng dụng cho iPhone part 19 - Pdf 70

366
Graphics: Quartz,
Core Animation,
and OpenGL
As we saw in the last chapter, creating and displaying images often isn’t enough. In
games and other more complex programs, you’ll also want to manipulate those
images in various ways at runtime. The iPhone
OS
offers two major ways to do this.
The first is through Quartz
2D
, a two-dimensional drawing library that allows for
complex line drawings, much as Canvas did on the web. It’s also the heart of the
Core Graphics frameworks. We already touched upon Quartz in the previous chap-
ter, when we drew images straight to the
CALayer
of a
UIView
; it’ll be the focus of
the majority of this chapter. Quartz also supports Core Animation functions, which
we’ll address somewhat more briefly.
This chapter covers

Using Quartz 2D for drawing

Understanding context, paths, and state

Using Core Animation

Learning about OpenGL ES
367The Quartz context

Context is a description of where the graphics are being written to, as defined by
a
CGContextRef
. You’ll usually be writing to a
UIView
or to a bitmap.
– Layers are a little less important for this overview, but they’re where Quartz
drawing occurs. They can be stacked one on top of another, creating a com-
plex result. When working with the iPhone, you’ll often only have a single
layer associated with each of your
UIKit
objects.

Paths are what you’ll typically be drawing within Quartz. These are collections of
lines and arcs that are drawn in advance, and then are “painted” to the screen
by either stroking or filling the path in question (or, possibly, by clipping it).

State saves the values of transformations, clipping paths, fill and stroke settings,
alpha values, other blending modes, text characteristics, and more. The current
state can be stored with
CGContextSaveGState
and restored with
CGContextRe-
storeGState
, allowing for easy switching among complex drawing setups.
Quartz is built on the older Core Foundation framework that we’ve met a few times
over the course of this part of the book. This means that you’ll need to use older styles
of variables to integrate with Cocoa Touch using toll-free bridging, and to respect
Core Foundation’s memory-management techniques. Take a look at the “Using Core
Foundation” sidebar in chapter 16 if you need a refresher on these topics.

drawRect:
method and, inside the object in question, you use
UIGraphicsGetCurrentContext
to
retrieve the current context.
You might alternatively create a bitmap context in order to create or modify an
image that you’ll use elsewhere in your program. You do this by using the
UIGraph-
icsBeginImageContext
and
UIGraphicsEndImageContext
functions.
There are a variety of Core Graphics functions that can be used to access other sorts of
contexts—types that you won’t usually use on an iPhone. The functions required to
capture a
PDF
context are one such example. These have two deficits that you should
be aware of: they depend more heavily on the Core Foundation frameworks and they
use Quartz’s inverted coordinate system.
One thing to note about graphical contexts is that they’re created in a stack: when
you create a new context, it’s pushed on top of a stack, and when you’re done with it,
it’s popped off. This means that if you create a new bitmap context, it’ll be placed on
top of any existing context, such as the one associated with your
UIView
, and will stay
there until you’re done with the bitmap.
Warning: inverse coordinate system ahead
By now, you should be familiar with the standard iPhone coordinate system. It has
the origin at the top left of the screen, with the main axes running to the right and
down. Quartz’s default coordinate system is inverted, with the origin at the bottom

PDF
s in this book, but we’re going to look at how to use each of
the
UIKit
context styles, starting with the
UIView
.
19.2.1 Drawing to a UIView
In chapter 18, we offered an introductory example of how to write to a
UIView
graphi-
cal context using the
drawRect:
method. That example was somewhat simplified
because the
UIKit
draw image commands mostly hide the idea of graphical contexts
from you. They automatically write to the current context, which inside
drawRect:
is
the context related to the
UIView
. For most other functions, you’ll need to do a bit
more work: retrieving the graphical context and passing that context along to any
drawing commands that you use.
Listing 19.1 shows how to draw a simple abstract face using this technique.
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
Table 19.1 Methods for graphical context creation

CGDictionaryRef
Creates a PDF
context
Listing 19.1 A few arcs drawn inside an existing context
370
C
HAPTER
19
Graphics: Quartz, Core Animation, and OpenGL
CGContextAddArc(ctx,110,50,30,0,2*M_PI,1);
CGContextAddArc(ctx,210,50,30,0,2*M_PI,1);
CGContextAddArc(ctx,160,110,15,0,2*M_PI,1);
CGContextAddArc(ctx,160,210,25,0,2*M_PI,1);
CGContextFillPath(ctx);
}
This example is fairly simple. You create a
UIView
subclass, and then you go to its
drawRect:
method. Once there, you capture the current context and use it to do
whatever Quartz
2D
drawing you desire.
The function calls won’t be familiar to you, but they’re
calls to draw a bunch of circles; we’ll discuss them in the
next section. As shown in figure 19.1, the art ends up look-
ing oddly abstract, which shows how Quartz draws continu-
ous paths. You see lines connecting one circle to the next, as
if the pencil never comes off the page, a topic we’ll talk
about more in the next section.

used in earlier programs.
- (void)viewDidLoad {
[super viewDidLoad];
UIGraphicsBeginImageContext(CGSizeMake(20,20));
Listing 19.2 A new context created to hold an image
Creates bitmap
context
B
Figure 19.1 The iPhone
does abstract art.
371Drawing paths
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextAddArc(ctx,10,10,10,0,2*M_PI,1);
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
CGContextFillPath(ctx);
UIImage *redBall =
UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *redBallView = [[UIImageView alloc] initWithImage:redBall];
redBallView.center = CGPointMake(160,330);
[self.view addSubview:redBallView];
}
Again, this example is simple. You could do this work anywhere you wanted, but we’ve
elected to use the
viewDidLoad
setup method. To start the process, you create an image
context, which is to say a bitmap
B
, and you immediately retrieve that context’s variable

,
y
,
radius
,
startangle
,
endangle
,
clockwise
Creates an arc, with the angles defined in radians.
A line will be drawn to the start point if there are
previous entries in the path, and from the end
point if there are additional entries.
The more complex functions
CGContextAdd-
ArcToPoint
,
CGContextAddCurveTo-
Point
, and
CGContextAddQuadCurveTo-
Point
allow for the creation of tangential arcs,
Bezier curves, and quadratic Bezier curves.
CGContextAddEllipseInRect context
,
CGRect
Creates an ellipse that fits inside the rectangle.
Retrieves new

CGContext
class refer-
ence. If you’re unfamiliar with Bezier and quadratic curves, take a look at our expla-
nation of the nearly identical Canvas functions in chapter 6 (section 6.2.2; particularly
figure 6.4, which depicts what both sorts of curves look like).
We’re going to move on from these simple drawing commands to the question of
what you do once you have a path. There are several options, beginning with the sim-
ple possibility of closing it and drawing it.
19.3.1 Finishing a path
As we’ve already noted, the path functions define the points and lines that make up a
drawing. When you’ve got that in hand, you have to do something with it. There are
three main choices: stroke the path, fill the path, or turn it into a clipping path. These
functions are all listed in table 19.3.
You’ll usually either stroke (outline) a path or fill it when you’re done. We used a
fill in each of our previous examples, but a stroke could have been substituted; the dif-
ference is that our circles wouldn’t have been filled in.
CGContextAddLineToPoint context
,
x
,
y
Creates a line from the current point to the desig-
nated end point.
The more complex
CGContextAddLines
func-
tion allows the addition of an array of lines.
CGContextAddRect context
,
CGRect

CGCon-
text
commands. There are equivalents to many of the simple
CGContext
functions, as
shown in table 19.4.
When you’re working with reusable paths, you first use the
CGPathCreateMutable
function to create a
CGPathRef
, and then you use
CGPath
commands to add lines or
Table 19.3 Functions for finishing a path
Function Arguments Summary
CGContextClosePath context
Draws a line from the end point of your path to the start
point, and then closes it. This is an optional final com-
mand that’s usually used when you’re stroking a path.
CGContextFillPath context
Closes your path automatically, and paints it by filling it
in.
CGContextEOFillPath
is an alternative that
does the filling in a slightly different way.
CGContextStrokePath context
Paints your path by stroking it.
CGContextClip context
Turns the current path into a clipping path.
Table 19.4

CGContextAddPath
function, which draws your stored path to your
graphical context, where it’ll abide by the normal rules.
Listing 19.3 shows how to use a mutable path to replace the
CGContext
commands
that we previously used in listing 19.1 to draw an abstract face. A more realistic exam-
ple would probably hold on to the path for use elsewhere; we released it here to
remind you of how Core Foundation memory management works.
- (void)drawRect:(CGRect)rect {
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath,NULL,110,50,30,0,2*M_PI,1);
CGPathMoveToPoint(myPath,NULL, 240, 50);
CGPathAddArc(myPath,NULL,210,50,30,0,2*M_PI,1);
CGPathAddArc(myPath,NULL,160,110,15,0,2*M_PI,1);
CGPathAddArc(myPath,NULL,160,210,25,0,2*M_PI,1);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextAddPath(ctx,myPath);
CGContextStrokePath(ctx);
CFRelease(myPath);
}
Of note here is the
NULL
that’s constantly being sent as a second argument to the
CGPath
commands. This argument is intended to be a
CGAffineTransform
variable. It
allows you to apply a transformation to the element being drawn, which is something

how to draw objects in more complex ways—by modifying state.
19.4 Setting the graphic state
The graphic state is how Quartz will be drawing. It includes a variety of information
such as what colors are being used for fills or strokes, which clipping paths constrain
the current drawing path, what transformations are being applied to the drawing, and
a number of other less important variables.
State is maintained in a stack. You can save a state at any time; it doesn’t change
how things are being drawn, but it does push that current state onto the top of a stack
for later retrieval. Later, you can restore a state, which pops the top state off the stack,
putting things back to how they were before the last save. We’ve mentioned these
functions before, but we’ve also listed them here in table 19.6.
As we’ve already noted, there are a lot of things that you can store in graphic state.
We’re going to cover many of them here, starting with colors.
19.4.1 Setting colors
In Quartz, you select colors by setting the fill color, the stroke color, or both in the cur-
rent graphical state. Once you’ve done this, any fill or stroke commands following the
color commands will appear in the appropriate colors. Note that color is irrelevant
while you are drawing the individual elements of a path—the color commands apply
only to the painting of the complete path at the end.
You can select colors from a variety of color spaces, which are different ways to
choose colors. They include
RGB
(red-green-blue),
RGBA
(red-green-blue-alpha),
CMYK
(cyan-magenta-yellow-black), and
CGC
olor (the underlying Core Graphics color
model). On the iPhone, you’ll usually want to either use the

The two RGB functions allow you to set a color using values from 0 to 1 for each of
red, green, blue, and alpha transparency (opacity). We saw an example of this in list-
ing 19.2:
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
The last two functions in table 19.7 allow you to set the color using any
CGColor
, and
you’ll understand how useful that is when you realize that you can read a
CGColor
property from any
UIColor
you create:
CGContextSetFillColorWithColor(ctx, [[UIColor redColor] CGColor]);
Given that you’re already familiar and comfortable with the
UIColor
s, we expect that
this latter function will be a popular one.
Having now covered the main ways to apply colors to your graphic state, we’re
ready to move on to the next topic: how to change how you draw through graphical
state transformations.
19.4.2 Making transformations
Transformations modify how you draw to your graphical context. They do this by chang-
ing the grid upon which you’re drawing by moving its origin, rotating, or resizing.
Why would you want to do these transformations?

They can be useful for drawing photographs (or other images), because the
transformations allow you to scale or rotate the picture.

They can make it a lot easier to do certain types of mathematical drawing. For
example, it’s probably easier to draw a symmetric mathematical construct if you’ve

,
alpha
Sets the stroke to the
RGBA value
CGContextSetFillColorWithColor context
,
CGColor
Sets the fill to the
CGColor
CGContextSetStrokeColorWithColor context
,
CGColor
Sets the stroke to the
CGColor
377Setting the graphic state
There are two gotchas that you should watch for.
First, note that the ordering of translations is somewhat pickier than the order of
color commands. You need to start your transformation before you add the relevant
lines to your path, and you need to maintain it until after you paint that path.
Second, although these transformations can be applied in any sequence, order
matters. Following are two transformation commands that could be applied together:
CGContextTranslateCTM(ctx, 100, 100);
CGContextRotateCTM(ctx, .25*M_PI);
These functions move a drawing 100 to the right and 100 down and rotate it by 45
degrees. Figure 19.2 shows the untransformed picture (which we’ve seen before), the
results if these commands are applied with the translation before the rotation, and the
results if they’re applied in the opposite order.
Table 19.8 CTM transformation functions that allow you to change how you draw
Function Arguments Summary
CGContextRotateCTM context


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status