4

I would like to draw an NSImage in a NSView drawRect in a simple tile pattern in my Cocoa mac app. One method to do this is simply write a loop to draw this image multiple times using drawInRect:fromRect:operation:fraction:

Is there a more direct method?

AmaltasCoder
  • 1,123
  • 3
  • 17
  • 35
  • See http://stackoverflow.com/q/1125230/643383 for a couple good answers to this question. – Caleb Feb 20 '12 at 05:59
  • Not quite a dup of that question because this one is about Cocoa, not Cocoa Touch. – rob mayoff Feb 20 '12 at 06:05
  • Agreed. That's important because in iOS windows very rarely resize but on the Mac it's a common occurrence. Window resizing affects pattern drawing due to the way the pattern origin is calculated. – Rob Keniger Feb 20 '12 at 10:05

3 Answers3

9

You need to use a pattern image as Kurt pointed out, but it's not as simple as that. Pattern images use the window's origin as their origin point, so if you resize the window the pattern will move.

You need to adjust the pattern phase in the current graphics context depending on where the view sits in the window. I use this category on NSView:

@implementation NSView (RKAdditions)
- (void)rk_drawPatternImage:(NSColor*)patternColor inRect:(NSRect)rect
{
    [self rk_drawPatternImage:patternColor inBezierPath:[NSBezierPath bezierPathWithRect:rect]];
}

- (void)rk_drawPatternImage:(NSColor*)patternColor inBezierPath:(NSBezierPath*)path
{
    [NSGraphicsContext saveGraphicsState];

    CGFloat yOffset = NSMaxY([self convertRect:self.bounds toView:nil]);
    CGFloat xOffset = NSMinX([self convertRect:self.bounds toView:nil]);
    [[NSGraphicsContext currentContext] setPatternPhase:NSMakePoint(xOffset, yOffset)];

    [patternColor set];
    [path fill];
    [NSGraphicsContext restoreGraphicsState];
}

@end

You'd use it like this:

-(void) drawRect: (NSRect)dirtyRect
{
    [self rk_drawPatternImage:[NSColor colorWithPatternImage:yourImage] inRect:self.bounds];
}
Rob Keniger
  • 45,830
  • 6
  • 101
  • 134
6
NSColor* myColor = [NSColor colorWithPatternImage:myImage];
[myColor set];
// then treat it like you would any other color, e.g.:
NSRectFill(myRect);
DarkDust
  • 90,870
  • 19
  • 190
  • 224
Kurt Revis
  • 27,695
  • 5
  • 68
  • 74
5

Kurt Revis's answer is the simplest way. If you need more control over how the image is tiled (you want to scale, rotate, or translate it), you can use CGContextDrawTiledImage. You will need to get a CGImageRef for the NSImage and you will need to get the CGContextRef of the current NSGraphicsContext.

Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848