如何计算iOS 7中的实际字体点大小(不是边界矩形)?

时间:2013-10-05 08:14:30

标签: ios objective-c iphone ios7

编辑:链接的“重复”问题仅涉及计算文本矩形。我需要在标签缩放后计算实际字体大小,而不是字符串大小。

现在不推荐使用此方法:

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

如何缩小适合的文本大小,在iOS 7中计算UILabel的字体大小?

8 个答案:

答案 0 :(得分:11)

我遇到了同样的问题,我需要知道实际的大小才能使我的UIView中的其他UILabel匹配。

我知道这不是一个完美的解决方案,但也许对你有用。

我的解决方案是:而不是使用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;

答案 1 :(得分:9)

从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;
}

我在我的应用程序中使用它来获取三个不同标签的字体大小,我需要保持大小同步,同时仍然允许它们自动缩小以进行本地化翻译,这些翻译可能比原始版本长得多英语同行。

我为每个标签调用一次该方法,然后如果它们不是全部相同的值,我将标签的字体大小设置为三者中的最小值。

答案 2 :(得分:8)

在iOS 6中的minFontSize以及iOS 7中的UILabel绘图添加中,不推荐使用NSString。如果您想使用它并查找使用的实际字体大小,您需要使用您在问题中提到的弃用方法。

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;

答案 3 :(得分:5)

扩展Ferran的回答

要展开以填充宽度或高度,无论它首先击中

Swift版

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's 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

目标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;
}

答案 4 :(得分:4)

我的具体任务是在启用了adjustsFontSizeToFitWidth的情况下,同等地调整2个标签上的字体大小。 该解决方案适用于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];
}

答案 5 :(得分:2)

下一个代码不支持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;
}

答案 6 :(得分:0)

单线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;

答案 7 :(得分:-1)

Erik van der Neut的代码对我有用,所以我将它翻译成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)
    }
}