CATextLayer + NSAttributtedString + CTParagraphStyleRef

catextlayer, core-animation, core-text, ios, objective-c

Solution

I tried your code, putting the NSAttributedString in a CATextLayer, and it ignored the formatting, as you said.

Then I tried drawing the exact same attributed string to a UIView `drawRect` method using `CTFrameDraw`, and it obeyed all your formatting. I can only assume that CATextLayer ignores the majority of its formatting. The CATextLayer Class Reference has a number of warnings about what it does in the interests of efficiency.

If you really need to draw to a `CALayer`, not a `UIView`, you may be able to create your own CALayer subclass or delegate and do the drawing there.

- (void)drawRect:(CGRect)rect
{
    //
    // Build attrStr as before.
    //

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];

    // Text ends up drawn inverted, so we have to reverse it.
    CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
    CGContextTranslateCTM( ctx, bounds.origin.x, bounds.origin.y+bounds.size.height );
    CGContextScaleCTM( ctx, 1, -1 );

    // Build a rectangle for drawing in.
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, bounds);

    // Create the frame and draw it into the graphics context
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) attrStr);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CFRelease(framesetter);
    CFRelease(path);

    // Finally do the drawing.
    CTFrameDraw(frame, ctx);
    CFRelease(frame);          
}

Problem

I want to have some text with a custom line-spacing, so I wrote an attribute string with `CTParagraphStyleAttributte` and pass it to my `CATextLayer`: ``` UIFont *font = [UIFont systemFontOfSize:20]; CTFontRef ctFont = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize, NULL); CGColorRef cgColor = [UIColor whiteColor].CGColor; CGFloat leading = 25.0; CTTextAlignment alignment = kCTRightTextAlignment; // just for test purposes const CTParagraphStyleSetting styleSettings[] = { {kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat), &leading}, {kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment} }; CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(styleSettings, 2)); NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys: (id)ctFont, (id)kCTFontAttributeName, (id)cgColor, (id)kCTForegroundColorAttributeName, (id)paragraphStyle, (id)kCTParagraphStyleAttributeName, nil]; CFRelease(ctFont); CFRelease(paragraphStyle); NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:string attributes:attributes]; _textLayer.string = attrStr; [attrStr release]; ``` But the line height is not changing. I think I am missing something here but I don't know what. I've tried with `kCTParagraphStyleSpecifierLineSpacingAdjustment` and `kCTParagraphStyleSpecifierLineSpacing` but either of them don't seem to work (?). I tried also to set the alignment using `kCTParagraphStyleSpecifierAlignment` (I know `CATextLayer` has a property for that) just to test `kCTParagraphStyleAttributeName` is indeed working and it didn't. I've noticed that even if I pass some crazy values (for example: `CTParagraphStyleCreate(styleSettings, -555);`) which leads me to ask myself: Does `CATextLayer` support paragraph attributes? If so, what am I missing here?

Original source