How to change an UILabel/UIFont's letter spacing?
Asked Answered
G

5

39

I've searched loads already and couldn't find an answer.

I have a normal UILabel, defined this way:

    UILabel *totalColors = [[[UILabel alloc] initWithFrame:CGRectMake(5, 7, 120, 69)] autorelease];
    totalColors.text = [NSString stringWithFormat:@"%d", total];
    totalColors.font = [UIFont fontWithName:@"Arial-BoldMT" size:60];
    totalColors.textColor = [UIColor colorWithRed:221/255.0 green:221/255.0 blue:221/255.0 alpha:1.0];
    totalColors.backgroundColor = [UIColor clearColor];
    [self addSubview:totalColors];

And I wanted the horizontal spacing between letters, to be tighter, whilst mantaining the font size.

Is there a way to do this? It should be a pretty basic thing to do.

Cheers guys, Andre

UPDATE:

So I was forced to do it like this:

- (void) drawRect:(CGRect)rect 
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSelectFont (context, "Arial-BoldMT", 60, kCGEncodingMacRoman);
    CGContextSetCharacterSpacing (context, -10);
    CGContextSetTextDrawingMode (context, kCGTextFill);

    CGContextSetRGBFillColor(context, 221/255.0, 221/255.0, 221/255.0, 221/255.0);
    CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
    CGContextSetTextMatrix(context, xform);

    char* result = malloc(17);
    sprintf(result, "%d", totalNumber);

    CGContextShowTextAtPoint (context, 0, 54, result, strlen(result));
}

But I need to align this to the right. I could do that manually if I knew the width of the drawn text, but it's proving near impossible to find that.

I've read about ATSU, but I couldn't find any examples.

This sucks :/

Glaucescent answered 30/3, 2010 at 12:2 Comment(5)
possible duplicate of #1063768Nombles
so there's no other way of doing it without using Custom fonts or without using Quartz 2D ?Glaucescent
You can get the size of region the text will occupy in a UILabel be calling - (CGSize)sizeWithFont:(UIFont *)font minFontSize:(CGFloat)minFontSize actualFontSize:(CGFloat *)actualFontSize forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode method of NSString Category UIStringDrawing. Then you can decrease that size by how much you shrunk your text, I guess. If you still need it :)Shortterm
If anyone needs a solution, check it here: https://mcmap.net/q/282264/-how-to-set-kerning-in-iphone-uilabelCompanion
Check out this answer to calculate kerning (attribute to tight space between characters) to fit label's width.Brahui
G
7

I've come up with a solution for the letter spacing and the alignment to the right.

Here it goes:

    NSString *number = [NSString stringWithFormat:@"%d", total];

    int lastPos = 85;

    NSUInteger i;
    for (i = number.length; i > 0; i--)
    {
        NSRange range = {i-1,1};
        NSString *n = [number substringWithRange:range];

        UILabel *digit = [[[UILabel alloc] initWithFrame:CGRectMake(5, 10, 35, 50)] autorelease];
        digit.text = n;
        digit.font = [UIFont fontWithName:@"Arial-BoldMT" size:60];
        digit.textColor = [UIColor colorWithRed:221/255.0 green:221/255.0 blue:221/255.0 alpha:1.0];
        digit.backgroundColor = [UIColor clearColor];
        [self addSubview:digit];

        CGSize textSize = [[digit text] sizeWithFont:[digit font]];
        CGFloat textWidth = textSize.width;

        CGRect rect = digit.frame;
        rect.origin.x = lastPos - textWidth;
        digit.frame = rect;

        lastPos = rect.origin.x + 10;
    }

The letter spacing is the "10" on the last line. The alignment comes from the lastPos.

Hope this helps anyone out there.

Glaucescent answered 30/3, 2010 at 15:33 Comment(1)
Your method is plausible (and the first that came up to my mind) but unfortunately it might not work well if you need to render many regions of text. I think the update provided by Andre is much better in the general caseShortterm
O
43

From iOS 6 you can use NSAttributedString in UILabel.

In attributed string you can use attribute NSKernAttributeName to set letter spacing

NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString: @"Test test test test "];
[attrStr addAttribute:NSKernAttributeName value:@(4.0) range:NSMakeRange(0, attrStr.length)];

UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 300, 300, 100)];
label.attributedText = attrStr;
Odelsting answered 3/12, 2013 at 10:53 Comment(1)
thanx for saving my time :) (y)Christmann
G
11

I've extended UILabel to change the character spacing. This should work out the box and pulls font, text, color etc from the UILabel itself (proper coding!).

You may notice I draw the text twice, first with clear color. This is to auto center the text in the label. Whilst this may be inefficient - isn't it nice to be auto centered?

Enjoy!

@interface RALabel : UILabel {
}
@end  

@implementation RALabel 

- (void) drawRect:(CGRect)rect 
{

    // Drawing code

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSASCIIStringEncoding], self.font.pointSize, kCGEncodingMacRoman);
    CGContextSetCharacterSpacing(context, 1);
    CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
    CGAffineTransform myTextTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1.f, -1.f );
    CGContextSetTextMatrix (context, myTextTransform);

    // draw 1 but invisbly to get the string length.
    CGPoint p =CGContextGetTextPosition(context);
    float centeredY = (self.font.pointSize + (self.frame.size.height- self.font.pointSize)/2)-2;
    CGContextShowTextAtPoint(context, 0, centeredY, [self.text cStringUsingEncoding:NSASCIIStringEncoding], [self.text length]);
    CGPoint v =CGContextGetTextPosition(context);

    // calculate width and draw second one.
    float width = v.x - p.x;
    float centeredX =(self.frame.size.width- width)/2;
    CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
    CGContextShowTextAtPoint(context, centeredX, centeredY, [self.text cStringUsingEncoding:NSASCIIStringEncoding], [self.text length]);

}
Goldarned answered 29/7, 2011 at 16:30 Comment(1)
you can only use ascii characters with this solutionSoule
G
7

I've come up with a solution for the letter spacing and the alignment to the right.

Here it goes:

    NSString *number = [NSString stringWithFormat:@"%d", total];

    int lastPos = 85;

    NSUInteger i;
    for (i = number.length; i > 0; i--)
    {
        NSRange range = {i-1,1};
        NSString *n = [number substringWithRange:range];

        UILabel *digit = [[[UILabel alloc] initWithFrame:CGRectMake(5, 10, 35, 50)] autorelease];
        digit.text = n;
        digit.font = [UIFont fontWithName:@"Arial-BoldMT" size:60];
        digit.textColor = [UIColor colorWithRed:221/255.0 green:221/255.0 blue:221/255.0 alpha:1.0];
        digit.backgroundColor = [UIColor clearColor];
        [self addSubview:digit];

        CGSize textSize = [[digit text] sizeWithFont:[digit font]];
        CGFloat textWidth = textSize.width;

        CGRect rect = digit.frame;
        rect.origin.x = lastPos - textWidth;
        digit.frame = rect;

        lastPos = rect.origin.x + 10;
    }

The letter spacing is the "10" on the last line. The alignment comes from the lastPos.

Hope this helps anyone out there.

Glaucescent answered 30/3, 2010 at 15:33 Comment(1)
Your method is plausible (and the first that came up to my mind) but unfortunately it might not work well if you need to render many regions of text. I think the update provided by Andre is much better in the general caseShortterm
H
3

In Swift:

let myTitle = "my title"
let titleLabel = UILabel()
let attributes: NSDictionary = [
    NSFontAttributeName:UIFont(name: "HelveticaNeue-Light", size: 20),
    NSForegroundColorAttributeName:UIColor.whiteColor(),
    NSKernAttributeName:CGFloat(2.0)
]
let attributedTitle = NSAttributedString(string: myTitle, attributes: attributes as? [String : AnyObject])

titleLabel.attributedText = attributedTitle
titleLabel.sizeToFit()
Hussy answered 17/11, 2015 at 22:20 Comment(0)
K
0

Not in any publicly available version of iPhone OS. ;-) If you are a current iPhone Developer, you can get an idea of where iPhone OS is going by looking through the "What's New" notes for iPhone OS 3.2.

Update: iOS v3.2, which added support for kerning, was still under NDA when I posted this. For an update-to-date answer, see How to set kerning in iPhone UILabel.

Kier answered 30/3, 2010 at 14:9 Comment(2)
You can determine the dimension of the text drawn in the UILabel using textRectForBounds:limitedToNumberOfLines:. Sounds like you found what you were looking for, though! I had just assumed you were looking for kerning. Happy coding!Kier
As of this date the current iOS version is 6.1. The way to accomplish this (easily) is through use NSAttributedString, but it was unavailable in most controls until iOS 6.0Riverside

© 2022 - 2024 — McMap. All rights reserved.