Sunday, July 18, 2010

Imagine you have a nice wooden texture that you want to use in some kind of navigation bar. You want the wooden texture to be repeatedly drawn along the x-axis. Your first approach might look something like this.

#import "PatternView.h"

@implementation PatternView

- (void)drawRect:(NSRect)dirtyRect {

[superdrawRect:dirtyRect];

NSImage *bg = [NSImageimageNamed:@"bg"];

NSColor *backgroundColor = [NSColorcolorWithPatternImage:bg];

[backgroundColor set];

NSRectFill([selfbounds]);

}

@end

This might not be what you have expected. Let me show you how the above code behaves in action.

(Click on the image above to see the video)

As you can see when resizing the window the displayed texture is changing as well. This is because of the fact that patterns are always drawn relative to the containing window. Of course this works fine for patterns that should repeat along both axes. In this case however, we don't want that. Let me show you how to fix that.

#import "PatternView.h"

@implementation PatternView

- (void)drawRect:(NSRect)dirtyRect {

[superdrawRect:dirtyRect];

NSSize size = [selfbounds].size;

// Create a new image and make it as big as the view

NSImage *bigImage = [[[NSImagealloc] initWithSize:size] autorelease];

// Prepare for drawing onto the new image

[bigImage lockFocus];

NSImage *bg = [NSImageimageNamed:@"bg"];

NSColor *backgroundColor = [NSColorcolorWithPatternImage:bg];

[backgroundColor set];

NSRectFill([selfbounds]);

[bigImage unlockFocus];

// Now draw the image to the view

[bigImage drawInRect:[selfbounds]

fromRect:NSZeroRect

operation:NSCompositeSourceOver

fraction:1.0f];

}

@end

﻿

The trick is to create a new empty image and size it correctly. Then you simply have to draw as shown in the first example. This results in exactly what we want.