4

I have a CALayer on which I draw some stuff at first and then a text:

- (void)drawInContext:(CGContextRef)context
{
    CGContextSaveGState(context);

    // draw things, everything displays correctly ...

    CGSize expectedCreditSize = [[gpData.credits stringValue] sizeWithFont:[UIFont 
                                                          systemFontOfSize:self.fontSize]];

    rect = CGRectMake(self.bounds.origin.x, self.bounds.size.height/2,
                      expectedCreditSize.width, expectedCreditSize.height);

    CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]);

    [self.creditString drawInRect:rect
                         withFont:[UIFont systemFontOfSize:self.fontSize]
                    lineBreakMode:NSLineBreakByWordWrapping
                        alignment:NSTextAlignmentRight];

    CGContextRestoreGState(context);
}

All the graphic stuff is shown correctly, but the text not at all. What am I doing wrong?

I also tried to add a CATextLayer as a subLayer, but therefore I get an error message at runtime.

CATextLayer *creditsTextLayer = [[CATextLayer alloc] init];
[creditsTextLayer setFrame:self.frame];
[creditsTextLayer setPosition:self.position];
[creditsTextLayer setString:self.creditString];
[creditsTextLayer setFontSize:self.fontSize];
[creditsTextLayer setAlignmentMode:kCAAlignmentLeft];
[creditsTextLayer setForegroundColor:[[UIColor whiteColor] CGColor]];
[self addSublayer:creditsTextLayer];

The only thing that worked is this solution:

CGContextSelectFont (context,
                     "Helvetica-Bold",
                     self.fontSize,
                     kCGEncodingMacRoman);
CGContextSetTextDrawingMode (context, kCGTextFill);

CGContextSetRGBFillColor (context, 0, 1, 0, .5);
CGContextSetRGBStrokeColor (context, 0, 0, 1, 1);
CGContextShowTextAtPoint (context, 40, 0, self.creditString, 9);

But this is very uncomfortable.

Has anybody an idea, what I can do to make one of my first suggestions to work? Am I missing something for displaying the text?

Thanks in advance!

edit:

based on Seamus answer I got this working now

- (void)drawInContext:(CGContextRef)context
{
    CGContextSaveGState(context);

    // draw things like circles and lines, 
    // everything displays correctly ...

    // now drawing the text
    UIGraphicsPushContext(context);

    CGSize expectedCreditSize = [[gpData.credits stringValue] sizeWithFont:[UIFont 
                                                          systemFontOfSize:self.fontSize]];

    rect = CGRectMake(self.bounds.origin.x, self.bounds.size.height/2,
                       expectedCreditSize.width, expectedCreditSize.height);

    CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]);

    [self.creditString drawInRect:rect
                         withFont:[UIFont systemFontOfSize:self.fontSize]
                    lineBreakMode:NSLineBreakByWordWrapping
                        alignment:NSTextAlignmentRight];

    UIGraphicsPopContext();
    CGContextRestoreGState(context);
}

That means that I just push and pop the graphics context for the text. Does this make sense? Why does it work for drawing other CGContext stuff? Maybe someone can explain…

clash
  • 532
  • 4
  • 17

1 Answers1

2

Observe that -drawInRect:withFont:lineBreakMode:alignment: does not take a CGContextRef parameter—it draws to the "current" graphics context. You don't show us how you got the context that you're drawing to, but typically that NSString method would be used in a -drawRect method with a context obtained like:

CGContextRef context = UIGraphicsGetCurrentContext();

You can make your context the "current context" with UIGraphicsPushContext() (but make sure you also call UIGraphicsPopContext()):

- (void)drawInContext:(CGContextRef)context
{
    UIGraphicsPushContext(context);
    CGContextSaveGState(context);

    // draw things, everything displays correctly ...

    CGSize expectedCreditSize = [[gpData.credits stringValue] sizeWithFont:[UIFont 
                                                          systemFontOfSize:self.fontSize]];

    rect = CGRectMake(self.bounds.origin.x, self.bounds.size.height/2,
                      expectedCreditSize.width, expectedCreditSize.height);

    CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]);

    [self.creditString drawInRect:rect
                         withFont:[UIFont systemFontOfSize:self.fontSize]
                    lineBreakMode:NSLineBreakByWordWrapping
                        alignment:NSTextAlignmentRight];

    CGContextRestoreGState(context);
    UIGraphicsPopContext();
}
marc_ferna
  • 5,837
  • 1
  • 18
  • 22
Seamus Campbell
  • 17,816
  • 3
  • 52
  • 60
  • Thx. I will try this tomorrow! I'm just wondering, because everything else I draw into this context before, is shown (lines, circles)... – clash Apr 04 '13 at 18:55
  • I just tried your solution and got a little modified version to work. I updated my question above. Maybe you can have a look at this please? I would like to understand the layers and drawing on them. – clash Apr 05 '13 at 07:06
  • Sorry, I tried to explain the "why" in the first paragraph. The other methods worked without the push/pop pair because they are functions that draw to a specific context—it's the first argument they take. `-drawInRect:withFont:lineBreakMode:alignment:` is different, it draws to an implicit context—the one on top of the `UIGraphics` current context stack. You can easily identify that this is the case by noticing that this function does not take a context as a parameter. This is why `CGContextShowTextAtPoint()` worked for you; it takes an explicit context. – Seamus Campbell Apr 05 '13 at 15:01