Как рассчитать фактический размер шрифта в iOS 7 (а не ограничивающий прямоугольник)?

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

Этот метод теперь устарел:

size = [self sizeWithFont:font // 20
              minFontSize:minFontSize // 14
           actualFontSize:&actualFontSize // 16
                 forWidth:maxWidth
            lineBreakMode:self.lineBreakMode];

Как я могу рассчитать размер шрифта UILabel теперь в iOS 7, когда он уменьшил размер текста, чтобы он поместился?

Ответ 1

У меня та же проблема, мне нужно знать фактический размер, чтобы другие UILabels в моем UIView совпадали.

Я знаю, что это не идеальное решение, но, возможно, оно полезно для вас.

Мое решение: вместо использования adjustsFontSizeToFitWidth Я вычисляю "вручную" размер.

CGSize initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
while ( initialSize.width > _label.frame.size.width ) {
    [_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
    initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
}
CGFloat actualSize = _label.font.pointSize;

Ответ 2

Отчужденный от Julius Bahr ответ на этой странице, этот метод отлично работает для получения фактического размера шрифта после его автоматической настройки:

- (CGFloat)getActualFontSizeForLabel:(UILabel *)label
{
    NSStringDrawingContext *labelContext = [NSStringDrawingContext new];
    labelContext.minimumScaleFactor = label.minimumScaleFactor;

    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:label.text attributes:@{ NSFontAttributeName: label.font }];
    [attributedString boundingRectWithSize:label.frame.size
                                   options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                   context:labelContext];

    CGFloat actualFontSize = label.font.pointSize * labelContext.actualScaleFactor;
    return actualFontSize;
}

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

Я вызываю этот метод один раз для каждой метки, а затем, если они не являются одинаковыми значениями, я устанавливаю размер шрифта ярлыка как минимум из трех.

Ответ 3

Использование minFontSize было устаревшим на UILabel в iOS 6 и в добавлениях NSString чертежей в iOS 7. Если вы хотите использовать его и найти фактический размер шрифта, вам нужно использовать устаревший метод, который вы упомянули в своем вопросе.

Замена minFontSize равна minimumScaleFactor. Если вы хотите найти фактический коэффициент масштабирования, вам нужно создать NSStringDrawingContext и передать его в сообщении boundingRectWithSize:options:attributes:context:, например:

NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
context.minimumScaleFactor = 0.7;
[label.text boundingRectWithSize:CGSizeMake(maxWidth, HUGE_VAL)
    options:NSStringDrawingUsesLineFragmentOrigin
    attributes:@{
        NSFontAttributeName: font
    } context:context];
CGFloat actualFontSize = font.pointSize * context.actualScaleFactor;

Ответ 4

Расширение ответа Феррана

Чтобы расширить ширину или высоту заливки, в зависимости от того, какая из них попадает в первую очередь

Быстрая версия

func getFontSizeToFitFrameOfLabel(label: UILabel) -> CGFloat
{
    var initialSize : CGSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])

    if initialSize.width > label.frame.size.width ||
       initialSize.height > label.frame.size.height
    {
        while initialSize.width > label.frame.size.width ||
              initialSize.height > label.frame.size.height
        {
            label.font = label.font.fontWithSize(label.font.pointSize - 1)
            initialSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])
        }
    } else {
        while initialSize.width < label.frame.size.width &&
              initialSize.height < label.frame.size.height
        {
            label.font = label.font.fontWithSize(label.font.pointSize + 1)
            initialSize = label.text!.sizeWithAttributes([NSFontAttributeName : label.font])
        }
        // went 1 point too large so compensate here
        label.font = label.font.fontWithSize(label.font.pointSize - 1)
    }
    return label.font.pointSize;
}

Затем сделайте что-нибудь подобное, чтобы использовать его (скажем, ваш ярлык называется title1Label)

 title1Label.frame = CGRect(x: 0.0, y: 0.0, width: view.frame.size.width, height: view.frame.size.height)
 // sets font to some nonzero size to begin with, it will change up or down to fit the label frame
 title1Label.font = UIFont(name: "Super Mario 256", size: 45.0)
 title1Label.font = title1Label.font.fontWithSize(getFontSizeToFitFrameOfLabel(title1Label))
 // resize height to be a little larger than the font height
 title1Label.frame.size.height = title1Label.font.pointSize*1.3

Версия Objective C:

- (CGFloat) maxFontSize:(UILabel *)label{
   CGSize initialSize = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];

   if (initialSize.width > label.frame.size.width ||
       initialSize.height > label.frame.size.height)
   {
       while (initialSize.width > label.frame.size.width ||
              initialSize.height > label.frame.size.height)
       {
           [label setFont:[label.font fontWithSize:label.font.pointSize - 1]];
           initialSize = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];
       }
   } else {
       while (initialSize.width < label.frame.size.width &&
              initialSize.height < label.frame.size.height)
       {
           [label setFont:[label.font fontWithSize:label.font.pointSize + 1]];
           initialSize = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];
       }
       // went 1 point too large so compensate here
       [label setFont:[label.font fontWithSize:label.font.pointSize - 1]];
   }
   return label.font.pointSize;
}

Ответ 5

Мой конкретный квест заключался в том, чтобы размер шрифта на 2 ярлыках был одинаковым с включенными настройкамиFontSizeToFitWidth. Решение работает на iOS 6 и 7.

+ (void)sizeLabelFontToMinSizeFor:(UILabel *)label1 and:(UILabel *)label2 {

NSStringDrawingContext *labelContext = [NSStringDrawingContext new];
labelContext.minimumScaleFactor = label1.minimumScaleFactor;

NSAttributedString *attributedString1 = [[NSAttributedString alloc] initWithString:label1.text attributes:@{NSFontAttributeName : label1.font}];
// the NSStringDrawingUsesLineFragmentOrigin and NSStringDrawingUsesFontLeading options are magic
[attributedString1 boundingRectWithSize:label1.frame.size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:labelContext];

CGFloat actualFontSize1 = label1.font.pointSize * labelContext.actualScaleFactor;

labelContext = [NSStringDrawingContext new];
labelContext.minimumScaleFactor = label2.minimumScaleFactor;

NSAttributedString *attributedString2 = [[NSAttributedString alloc] initWithString:label2.text attributes:@{NSFontAttributeName : label2.font}];
[attributedString2 boundingRectWithSize:label2.frame.size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:labelContext];

CGFloat actualFontSize2 = label2.font.pointSize * labelContext.actualScaleFactor;

CGFloat minSize = MIN(actualFontSize1, actualFontSize2);

label1.font = [UIFont fontWithName:RCDefaultFontName size:minSize];
label2.font = [UIFont fontWithName:RCDefaultFontName size:minSize];
}

Ответ 6

Следующий код не поддерживает minFontSize и lineBreakMode, поэтому, если вам это нужно, вы должны улучшить его самостоятельно:

CGSize NSString_sizeWithFont(NSString * str, UIFont *font) {
    CGSize result;
    if (NO == [str respondsToSelector: @selector(sizeWithAttributes:)]) {
        // legacy way
        result = [str sizeWithFont: font];
    } else {
        // modern way
        NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
                               font, NSFontAttributeName, nil];
        result = [str sizeWithAttributes: dict];
    }
    return result;
}

UIFont * NSString_calcActualFont(NSString * str, UIFont * initialFont,
                                 CGSize sizeLimit, CGSize * actualSize)
{
    const CGSize curSize = NSString_sizeWithFont(str, initialFont);

    CGFloat actualFontSize = initialFont.pointSize;
    actualFontSize *= MIN(sizeLimit.width / curSize.width, sizeLimit.height / curSize.height);

    UIFont * actualFont = [initialFont fontWithSize: floorf(actualFontSize)];
    *actualSize = NSString_sizeWithFont(str, actualFont);

    return actualFont;
}

Ответ 7

Простое решение для однострочной UILabel:

//myLabel - initial label

UILabel *fullSizeLabel = [UILabel new];
fullSizeLabel.font = myLabel.font;
fullSizeLabel.text = myLabel.text;
[fullSizeLabel sizeToFit];

CGFloat actualFontSize = myLabel.font.pointSize * (myLabel.bounds.size.width / fullSizeLabel.bounds.size.width);

//correct, if new font size bigger than initial
actualFontSize = actualFontSize < myLabel.font.pointSize ? actualFontSize : myLabel.font.pointSize;

Ответ 8

Код Эрика ван дер Нейта работал у меня, поэтому я перевел его в Swift и завернул в расширение UILabel:

extension UILabel {

    public func actualFontSize()-> CGFloat {
        let context = NSStringDrawingContext()
        context.minimumScaleFactor = self.minimumScaleFactor

        let attributedString = NSAttributedString(string: self.text ?? "", attributes: [NSFontAttributeName: self.font])
        attributedString.boundingRectWithSize(self.frame.size, options: [.UsesLineFragmentOrigin], context: context)

        return (self.font.pointSize * context.actualScaleFactor)
    }
}