Online Book Reader

Home Category

Learn Objective-C on the Mac - Mark Dalrymple [132]

By Root 1030 0
setting the line width is done through a method on the path itself, setting the color looks like a sort of free-floating operation. You just send any color the set message, and suddenly it’s the current color! What’s happening is that NSColor’s set method interacts with the underlying graphics context, setting the color that will be used for subsequent drawing operations. One consequence of this is that NSColor’s set method will only do something useful while there is a current graphics context, such as within a drawRect: method. Another consequence is that the current color is a property (in a general sense, if not an Objective-C language sense) of the graphics context, so whatever color was set before our method is saved at the beginning of our method when [NSGraphicsContext saveGraphicsState] is called, and restored at the end when [NSGraphicsContext restoreGraphicsState] is called, putting everything back in order again.

At this point, if you Build & Run the application, you’ll see that it draws a white rect with a black outline (Figure 13-4).

Figure 13-4. The shape of things to come

Beyond Color


Now let’s continue, and start drawing the head. Add these lines to the drawRect: method, toward the end but still before the [NSGraphicsContext restoreGraphicsState] call:

Here we are once again using CGRectInset to make a new rect that is smaller than our bounds, this time to create an oval shape for Mr Smiley’s head. After creating a Bezier path, we create something new, an instance of NSGradient, which knows how to take two or more colors and draw a smooth gradient between them. In this example, you see that it can draw itself across the inner surface of a Bezier path. Build & Run this code, and you’ll see that our view now contains a round “head” with a shaded gradient (Figure 13-5).

Figure 13-5. The basic head shot

Manual Path Construction


Now all that’s left is to draw the facial features (a simple mouth and eyes). Add these lines to the end of drawRect: (but before the final [NSGraphicsContext restoreGraphicsState] call):

Here, instead of using one of the convenient class methods on NSBezierPath to get a complete shape right away, we are using some more basic methods to construct a path out of nothing. The moveToPoint: method positions a virtual “pen” at the specified point, without drawing a line to it. And lineToPoint: draws a line from the path’s current point to the new point. In reality, these methods don’t do any drawing; they simply build up the Bezier path structure that is later drawn by the stroke method.

One additional finesse here is that we set the line cap style. This setting defines what happens at the ends of lines. This is especially important for the eyes, which are drawn as a single point. Using the default setting, which lops off everything precisely where the line segment ends, the eyes were completely invisible, but using NSRoundLineCapStyle gives us a perfect tiny circle for each eye. Build & Run to see the final result (Figure 13-6).

Figure 13-6. Mr Smiley. He really is happy, I’m sure of it!

Pushing Boundaries


Now that SmileyView is drawing a perfect happy face, naturally we’ll want to be able to resize this to fit it into different spots. Switch back to MainMenu.xib in Interface Builder, and configure the SmileyView’s autosize properties so that it autosizes fully with the window. Do this by selecting the SmileyView, opening the Size Inspector, and clicking the parts of the autosize control so that all the red arrows and lines are “lit”. Save your work, go back to Xcode and Build & Run, and resize your view (Figure 13-7).

Figure 13-7. Oops upside your head!

Now that doesn’t seem right, does it? The problem is that our in our drawRect: method, we have a bit of a mix’n’match approach when specifying path geometry. For the outline and the head shape, we base everything on the bounds rect, but for the facial features we’re hard-coding numeric pixel widths. When the view resizes, our bounds rect automatically resizes along with it. This

Return Main Page Previous Page Next Page

®Online Book Reader