views:

281

answers:

1

I have a UIView subclass that instantiates three sibling sublayers of its layer. Two of the sublayers have their content set to images files; and the third has a graphic drawn in the

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

method. The problem is that my drawing layer always appears behind the image layers. I've tried reordering the sublayers array and altering the zPosition properties of the sublayers to no avail. What am I missing?

- (void)setupLayers
{
    CALayer *rootLayer = [self layer];

    _meterLayer = [CALayer layer];
    [_meterLayer setContents:(id)[[UIImage imageNamed:@"HealthMeterRadial60x60.png"] CGImage]];

    _pointerLayer = [CALayer layer];
    [_pointerLayer setContents:(id)[[UIImage imageNamed:@"HealthMeterRadialPointer60x60.png"] CGImage]];

    _labelLayer = [CALayer layer];
    [self set_labelText:@"Health"];

    [rootLayer addSublayer:_meterLayer];
    [rootLayer insertSublayer:_pointerLayer above:_meterLayer];
    [rootLayer insertSublayer:_labelLayer above:_pointerLayer];
}

And the drawLayerInContext method:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    if( layer = _labelLayer) {
     //draw graphics ... omitted for clarity; works, but always behind images

    }
}
+1  A: 

The solution to the problem is to draw the content of _labelLayer to an image context and set it's content property to the resulting CGImage. When setting up the layers:

//  create a layer for the name of the meter
_labelLayer = [CALayer layer];
[_labelLayer setFrame:CGRectMake(0, 0, rootLayer.frame.size.width, rootLayer.frame.size.height)];
[self set_labelText:@"Health"];
[_labelLayer setContents:(id)[[self labelImageContent] CGImage]];

Then to draw the contents to a CGImage:

- (UIImage *)labelImageContent {

NSAssert( _labelText != nil, @"No label set for radial meter");
// get a frame for our layer and start a context to make an image
CGRect rect = _labelLayer.frame;
UIGraphicsBeginImageContext(rect.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();

// measure the size of our text first to know where to position
CGSize textsize = [_labelText sizeWithFont:[UIFont systemFontOfSize:10]];
const char *text = [_labelText cStringUsingEncoding:NSUTF8StringEncoding];
size_t textlen = strlen(text);

// this is just a testing rectangle
CGContextSetRGBFillColor(ctx, 1, 0, 0, 0.5);
CGContextFillRect(ctx,rect);

/*  save our context before writing text  */
CGContextSaveGState(ctx);

CGContextSelectFont(ctx, "Helvetica", 9, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(ctx, kCGTextFill);

/*  this will flip our text so that it is readable  */
CGAffineTransform flipTransform = CGAffineTransformMakeTranslation(0.0f, rect.size.height);
flipTransform = CGAffineTransformScale(flipTransform, 1.0f, -1.0f);

// write our title in black
float opaqueBlack[] = {0,0,0,1};
CGContextSetFillColor(ctx, opaqueBlack);
CGContextConcatCTM(ctx, flipTransform);
CGContextShowTextAtPoint(ctx, rect.origin.x + 0.5*(60-textsize.width), rect.origin.y + 40 - 0.5 * textsize.height - 5, text, textlen);

/*  get our graphics state back  */
CGContextRestoreGState(ctx);

UIImage *labelPic = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return labelPic;

}

df

alan