I would like to use a CATiledLayer in iPhone OS 3.1.3 and to do so all drawing in -(void)drawLayer:(CALayer *)layer inContext:(CGContext)context
has to be done
Thomas, I started by following the WWDC 2010 ScrollView talk and there is little or no documentation on working within drawLayer:inContext
for iOS 3.x. I had the same issues as you do when I moved the demo code from drawRect:
across to drawLayer:inContext:
.
Some investigation showed me that within drawLayer:inContext:
the size and offset of rect
returned from CGContextGetClipBoundingBox(context)
is exactly what you want to draw in. Where drawRect:
gives you the whole bounds.
Knowing this you can remove the row and column iteration, as well as the CGRect intersection for the edge tiles and just draw to the rect once you've translated the context.
Here's what I've ended up with:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGRect rect = CGContextGetClipBoundingBox(ctx);
CGFloat scale = CGContextGetCTM(ctx).a;
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
CGSize tileSize = tiledLayer.tileSize;
tileSize.width /= scale;
tileSize.height /= scale;
int col = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
int row = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);
CGImageRef image = [self imageForScale:scale row:row col:col];
if(NULL != image) {
CGContextTranslateCTM(ctx, 0.0, rect.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
rect = CGContextGetClipBoundingBox(ctx);
CGContextDrawImage(ctx, rect, image);
CGImageRelease(image);
}
}
Notice that rect
is redefined after the TranslateCTM
and ScaleCTM
.
And for reference here is my imageForScale:row:col
function:
- (CGImageRef) imageForScale:(CGFloat)scale row:(int)row col:(int)col {
CGImageRef image = NULL;
CGDataProviderRef provider = NULL;
NSString *filename = [NSString stringWithFormat:@"img_name_here%0.0f_%d_%d",ceilf(scale * 100),col,row];
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"png"];
if(path != nil) {
NSURL *imageURL = [NSURL fileURLWithPath:path];
provider = CGDataProviderCreateWithURL((CFURLRef)imageURL);
image = CGImageCreateWithPNGDataProvider(provider,NULL,FALSE,kCGRenderingIntentDefault);
CFRelease(provider);
}
return image;
}
There's still a bit of work to be done on these two functions in order to support high resolution graphics properly, but it does look nice on everything but an iPhone 4.