I\'ve been scouring the Internet for a while now for information on how one can alter the letter-spacing/kerning of a font within UIKit.
My fear is, that like using
The main problem of CGContextShowText methods - they are diaplays only ASCII strings. To display UTF strings you need to map your string symbols to glyphs and show glyphs.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSASCIIStringEncoding], self.font.pointSize, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, characterSpacing);
CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
CGAffineTransform myTextTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1.f, -1.f );
CGContextSetTextMatrix (context, myTextTransform);
CGGlyph glyphs[self.text.length];
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)self.font.fontName, self.font.pointSize, NULL);
CTFontGetGlyphsForCharacters(fontRef, (const unichar*)[self.text cStringUsingEncoding:NSUnicodeStringEncoding], glyphs, self.text.length);
float centeredY = (self.font.pointSize + (self.frame.size.height- self.font.pointSize)/2)-2;
CGContextShowGlyphsAtPoint(context, rect.origin.x, centeredY, (const CGGlyph *)glyphs, self.text.length);
You may be able to do what you need using Quartz 2D. Specifically, the CGContextSetCharacterSpacing
property can control spacing between letters. I'm not sure about kerning though.
Quartz 2D Programming Guide: Text
I landed here from Google trying to do the same with UITextField. I implemented something that'll work generically for UILabel below.
@interface AdjustableUILable : UILabel {
CGFloat characterSpacing;
}
@property CGFloat characterSpacing;
@end
@implementation AdjustableUILable
@synthesize characterSpacing;
- (void)drawTextInRect:(CGRect)rect
{
if (characterSpacing)
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat size = self.font.pointSize;
CGContextSelectFont (context, [self.font.fontName UTF8String], size, kCGEncodingMacRoman);
CGContextSetCharacterSpacing (context, characterSpacing);
CGContextSetTextDrawingMode (context, kCGTextFill);
// Rotate text to not be upside down
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, xform);
const char *cStr = [self.text UTF8String];
CGContextShowTextAtPoint (context, rect.origin.x, rect.origin.y + size, cStr, strlen(cStr));
}
else
{
// no character spacing provided so do normal drawing
[super drawTextInRect:rect];
}
}
@end
Then to use it, just set up the label in viewDidLoad or something
- (void)viewDidLoad
{
myLabel.characterSpacing = 2; // point size
}
I tried it with UITextField, but unfortunately it only adds the character spacing after the user has edited the field. -drawTextInRect is only called after the -textFieldShouldEndEditing delegate method. From other forums some suggested this was because UITextField needs to know the rendering of the font in order to display the cursor. Never found a solution for that piece...
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]);
}
The accepted answer lost a lot of the formatting, and user363349's answer mostly worked for me but text alignment wasn't working. I modified the code to fix that:
- (void) drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSASCIIStringEncoding], self.font.pointSize, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, characterSpacing);
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 destX = 0;
// calculate X position based on alignment
if([self textAlignment] == UITextAlignmentLeft){
destX = 0;
}else if([self textAlignment] == UITextAlignmentCenter){
destX = (self.frame.size.width- width)/2;
}else if([self textAlignment] == UITextAlignmentRight){
destX = self.frame.size.width - width;
}
CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
CGContextShowTextAtPoint(context, destX, centeredY, [self.text cStringUsingEncoding:NSASCIIStringEncoding], [self.text length]);
}