Posts Tagged drawing
Custom Drawing Using drawRect, Part 1
Posted by Michael in Cocoa, Design, Sample Code on December 18, 2009
One of the more advanced techniques for creating custom user interfaces on the Mac is the use of NSView’s drawRect method. Many answers to questions on StackOverflow and Apple’s mailing lists include recommendations to “just override drawRect and do the drawing yourself”. Some folks see this recommendation and their eyes glaze over, thinking that it’s too advanced of a technique for them to wrap their heads around. Over the next few days I’m going to go over some basic techniques that can yield powerful results.
Let’s start by setting up the Xcode project that will be the basis of the rest of these posts.
- Open Xcode and create a new Cocoa Application project called DrawingSample.
- Create a new NSView subclass called CustomDrawingView.
- Open MainMenu.xib, add a new Custom View to the Main Window, set its class to be CustomDrawingView, and set it’s autosizing flags as seen here:
Save and Quit Interface Builder and switch back to Xcode. Open CustomDrawingView.m, it should look like so:
@implementation CustomDrawingView - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code here. } return self; } - (void)drawRect:(NSRect)dirtyRect { // Drawing code here. } @end
We’re going to start (and finish) today with just a simple concept and some basic drawing that will set the stage for the future posts. All drawing in Cocoa is done by first setting up the environment in which you want to draw, and then doing the actual drawing. For instance, if we want to draw a blue box, we first have to setup the color blue, define the bounds of the box, and then draw it. In this case we are using the NSRect that is passed to the drawRect method as the box we want to draw, and we setup the color blue by calling [[NSColor blueColor] set]. We then use the convenience method NSRectFill to fill the dirtyRect with the color blue. Notice that we didn’t pass the color to NSRectFill, we set it, and from then on anything we draw will be blue until we change the color.
You can think of drawing in Cocoa much the same way as you would think of painting with a brush. You dip your brush in a certain paint color, paint the shape you want to paint, and then dip your brush in a new color and paint some more.
- (void)drawRect:(NSRect)dirtyRect { [[NSColor blueColor] set]; NSRectFill(dirtyRect); }
The preceding code, when run, will generate a view that looks like this:
Now, this may not look like much, but in future posts we will build on these concepts and, hopefully, by the end have drawn some pretty cool and useful things.
Standard iPhone Element Sizes
Great quick reference for Standard iPhone Element Sizes at Jonathan George‘s site.
Quick and Easy Drawing Performance Debugging with NSShowAllDrawing
While watching one of the WWDC09 session videos I was informed of a great tip that I had been previously unknown to me: Pass -NSShowAllDrawing YES as an argument to your application in Xcode to see a visual representation of the drawing that your application performs as it runs.
To illustrate how NSShowAllDrawing works and the issues it can help you correct I’ve put together two videos. The first shows my app, Bezipped, in its current 1.0 state and its current drawing behavior.
This second video shows how I improved the drawing in Bezipped simply by setting the top-level container to be backed by a Core Animation layer:
I highly recommend giving your app a spin with NSShowAllDrawing if you haven’t already, it was certainly a real eye-opener for me. There are some additional resources for debugging your drawing performance on OS X (as pointed out to me by André Pang) provided by Apple here: Drawing Performance Guidelines: Measuring Drawing Performance
Lastly, both Alan Rogers and Steve Streza pointed me towards Quartz Debug.app (included with the developer tools) as another means to see similar redrawing behavior. I found Quartz Debug’s options to be a bit heavy-handed as the drawing performance of the entire OS was shown instead of just my app, but your mileage may vary.
