38

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 :/

Andre
  • 4,417
  • 8
  • 32
  • 37
  • possible duplicate of http://stackoverflow.com/questions/1063268/is-it-possible-to-alter-the-letter-spacing-kerning-of-a-font-with-cocoa-touch – Can Berk Güder Mar 30 '10 at 12:20
  • so there's no other way of doing it without using Custom fonts or without using Quartz 2D ? – Andre Mar 30 '10 at 13:03
  • 1
    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 :) – Kostiantyn Sokolinskyi Apr 12 '11 at 15:02
  • If anyone needs a solution, check it here: http://stackoverflow.com/a/35156265/4173671 – Arben Pnishi Feb 03 '16 at 14:22
  • Check out [this answer](https://stackoverflow.com/a/46517511/1223728) to calculate kerning (attribute to tight space between characters) to fit label's width. – Borzh Oct 01 '17 at 22:37

5 Answers5

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;
Krizai
  • 610
  • 10
  • 18
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]);

}
user363349
  • 1,228
  • 14
  • 16
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.

Andre
  • 4,417
  • 8
  • 32
  • 37
  • 3
    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 case – Kostiantyn Sokolinskyi Apr 12 '11 at 14:58
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()
CodeOverRide
  • 4,431
  • 43
  • 36
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.

Community
  • 1
  • 1
Zack
  • 1,256
  • 9
  • 20
  • 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! – Zack Mar 31 '10 at 19:39
  • 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.0 – DBD Feb 19 '13 at 15:58