NSString drawInRect:withAttributes: not correctly centered when using NSKernAttributeName
Asked Answered
N

1

4

When I use drawInRect:withAttributes: and pass in both a paragraph style with NSTextAlignmentCenter and a non-zero value for NSKernAttributeName, the string does not get centered correctly. Am I doing something wrong or is this expected behavior? Is there a workaround?

Screenshot:

enter image description here

You can clearly see that top text is not centered correctly.

My demo code:

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    UIFont *font = [UIFont systemFontOfSize:15.0];
    [self drawString:@"88" inRect:rect font:font textColor:[UIColor blackColor]];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextAddRect(context, rect);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

- (void)drawString:(NSString *)text
            inRect:(CGRect)contextRect
              font:(UIFont *)font
         textColor:(UIColor *)textColor
{
    CGFloat fontHeight = font.lineHeight;
    CGFloat yOffset = floorf((contextRect.size.height - fontHeight) / 2.0) + contextRect.origin.y;

    CGRect textRect = CGRectMake(contextRect.origin.x, yOffset, contextRect.size.width, fontHeight);

    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    paragraphStyle.lineBreakMode = NSLineBreakByClipping;
    paragraphStyle.alignment = NSTextAlignmentCenter;

    [text drawInRect:textRect withAttributes:@{NSKernAttributeName: @(self.kerning),
                                            NSForegroundColorAttributeName: textColor,
                                            NSFontAttributeName: font,
                                            NSParagraphStyleAttributeName: paragraphStyle}];
}

Thanks!

Update, thanks to this comment, I added NSBackgroundColorAttributeName: [UIColor greenColor] to the attributes and got the following result:

enter image description here

Nitroso answered 19/5, 2014 at 15:39 Comment(3)
I'm wondering, if you add to the draw NSBackgroundColorAttributeName, it's "centered" in it.Starstudded
Good observation, that's true! But that's even a different bug then: Because the background color is not applied to the whole text.Nitroso
Could you provide a screenshot with that (with the 2 cases)? It was just a guess. But I figured that could help. I often provide a flashy background color to some UI elements to check their frames, so I just suggest the same here.Starstudded
B
13

The kerning must be applied only to the first character of each kerning pair. If you want to display a string with kerning between all n characters then the kerning attribute must be set for the first n-1 characters.

Instead of:

[text drawInRect:textRect withAttributes:@{NSKernAttributeName: @(self.kerning),
                                        NSForegroundColorAttributeName: textColor,
                                        NSFontAttributeName: font,
                                        NSParagraphStyleAttributeName: paragraphStyle}];

you have to create an attributed string so that you can set the kerning attribute for a specific range instead of the entire string:

NSMutableAttributedString *as = [[NSMutableAttributedString alloc]
                                 initWithString:text
                                 attributes:@{
                                              NSForegroundColorAttributeName: textColor,
                                              NSFontAttributeName: font,
                                              NSParagraphStyleAttributeName: paragraphStyle}];
[as addAttribute:NSKernAttributeName
           value:@(self.kerning)
           range:NSMakeRange(0, [text length] - 1)];

[as drawInRect:textRect];

Here the result for the string "1234" and kerning -4.0:

enter image description here

Bureau answered 19/5, 2014 at 17:40 Comment(3)
Thank you so much! That is perfect! I was also looking for a "tracking" instead of a "kerning" attribute, but I didn't find one.Nitroso
@JohannesFahrenkrug: What do you mean by "tracking"?Bureau
Kerning is for specific letter pairs, tracking is more general: graphics.com/article-old/…Nitroso

© 2022 - 2024 — McMap. All rights reserved.