【问题标题】:How to calculate actual font point size in iOS 7 (not the bounding rectangle)?如何计算 iOS 7 中的实际字体点大小(不是边界矩形)?
【发布时间】:2013-10-12 07:07:47
【问题描述】:

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

此方法现已弃用:

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

现在在 iOS 7 中,当 UILabel 缩小文本大小以适应时,如何计算 UILabel 的字体大小?

【问题讨论】:

标签: ios objective-c iphone ios7


【解决方案1】:

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

【讨论】:

    【解决方案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;
    }
    

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

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

    【讨论】:

    • 你会怎么称呼这个?在layoutSubviews 中使用它会返回默认字体大小而不是调整后的大小。
    • richsage,在所有情况下,我都会在视图控制器的 -viewWillLayoutSubviews 方法的末尾调用它,它对我来说非常有效。
    【解决方案3】:

    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)
        }
    }
    

    【讨论】:

    • 选项应包括.UsesFontLeading
    【解决方案4】:

    扩展 Ferran 的答案

    扩展以填充宽度或高度,以先命中者为准

    斯威夫特版本

    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
    

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

    【讨论】:

    • 经过 1.5 小时的搜索后,在获取实际点大小时,这确实有效。谢谢
    【解决方案5】:

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

      我的具体任务是在启用 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];
      }
      

      【讨论】:

        【解决方案7】:

        我有同样的问题,我需要知道实际大小才能使我的 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;
        

        【讨论】:

          【解决方案8】:

          minFontSize 的使用在 iOS 6 中的 UILabel 和 iOS 7 中的 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;
          

          【讨论】:

          猜你喜欢
          • 2017-11-08
          • 1970-01-01
          • 1970-01-01
          • 2021-03-07
          • 2019-08-11
          • 1970-01-01
          • 2019-06-23
          • 2012-04-15
          • 1970-01-01
          相关资源
          最近更新 更多