Можно ли изменить межбуквенный интервал / кернинг шрифта с помощью Cocoa Touch? - PullRequest
15 голосов
/ 30 июня 2009

Я некоторое время искал в Интернете информацию о том, как можно изменить межбуквенный интервал / кернинг шрифта в UIKit.

Я боюсь, что, как и использование собственных шрифтов, вы просто не можете. Что было бы ужасной новостью.

Я знаю, что Apple защищает нас от плохого дизайна этими ограничениями, но они также мешают нам реализовать действительно отличный дизайн.

Что люди предлагают мне сделать?

  1. Используйте шрифт со стандартным кернингом, люди, вероятно, в любом случае не заметят разницу.

  2. Найдите чей-то взломанный класс, чтобы получить вид, которого заслуживает пользователь после расставания с его тяжело заработанными деньгами.

  3. Используйте метод, который я каким-то образом упустил, и сделайте это с UIKit, обещая мою вечную благодарность человеку, который передает этот скрытый слепок знаний.

Ответы [ 5 ]

4 голосов
/ 19 августа 2012

Принятый ответ потерял большую часть форматирования, и ответ user363349 в основном работал для меня, но выравнивание текста не работало. Я изменил код, чтобы исправить это:

- (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]);
}
4 голосов
/ 11 октября 2011

Я попал сюда из Google, пытаясь сделать то же самое с UITextField. Я реализовал что-то, что будет работать в общем случае для UILabel ниже.

@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

Затем, чтобы использовать его, просто установите метку в viewDidLoad или что-то в этом роде

- (void)viewDidLoad
{
        myLabel.characterSpacing = 2; // point size
}

Я пробовал это с UITextField, но, к сожалению, он добавляет интервал между символами только после того, как пользователь отредактировал поле. -drawTextInRect вызывается только после метода делегата -textFieldShouldEndEditing. На других форумах некоторые высказывали предположение, что это связано с тем, что UITextField должен знать отображение шрифта для отображения курсора. Никогда не нашел решения для этой штуки ...

3 голосов
/ 29 июля 2011

Я расширил UILabel, чтобы изменить интервал между символами. Это должно сработать и получить шрифт, текст, цвет и т. Д. Из самой UILabel (правильное кодирование!).

Вы можете заметить, что я рисую текст дважды, сначала четким цветом. Это делается для автоматического центрирования текста в метке. Хотя это может быть неэффективно - разве это не хорошо, если автоцентрироваться?

Наслаждайтесь!

@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]);

}
3 голосов
/ 30 июня 2009

Вы можете делать то, что вам нужно, используя Quartz 2D. В частности, свойство CGContextSetCharacterSpacing может контролировать интервал между буквами. Я не уверен насчет кернинга.

Руководство по программированию Quartz 2D: Текст

1 голос
/ 22 августа 2012

Основная проблема методов CGContextShowText - они отображают только строки ASCII. Чтобы отобразить строки UTF, вам необходимо отобразить символы строки на глифы и показать глифы.

    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);
...