【问题标题】:How to adjust font size of label to fit the rectangle?如何调整标签的字体大小以适合矩形?
【发布时间】:2011-02-20 03:00:33
【问题描述】:

是的,有这个很酷的myLabel.adjustsFontSizeToFitWidth = YES; 属性。但是只要标签有两行或更多行,它就不会将文本调整为任何内容。所以如果它不适合矩形,它就会被截断。

还有其他方法吗?

【问题讨论】:

    标签: iphone uilabel


    【解决方案1】:

    这是 UILabel 的 Swift 扩展。它运行二进制搜索算法来调整标签的字体和边界,并经过测试可在 iOS 12 上运行。

    用法:调整字体大小以适应 100x100 的大小(精确到 1.0 字体点)并将其与顶部对齐。

    let adjustedSize = <label>.fitFontForSize(CGSizeMake(100, 100))
    <label>.frame = CGRect(x: 0, y: 0, width: 100, height: adjustedSize.height)
    

    将以下内容复制/粘贴到您的文件中:

    extension UILabel {
        @discardableResult func fitFontForSize(_ constrainedSize: CGSize,
                                               maxFontSize: CGFloat = 100,
                                               minFontSize: CGFloat = 5,
                                               accuracy: CGFloat = 1) -> CGSize {
            assert(maxFontSize > minFontSize)
    
            var minFontSize = minFontSize
            var maxFontSize = maxFontSize
            var fittingSize = constrainedSize
    
            while maxFontSize - minFontSize > accuracy {
                let midFontSize: CGFloat = ((minFontSize + maxFontSize) / 2)
                font = font.withSize(midFontSize)
                fittingSize = sizeThatFits(constrainedSize)
                if fittingSize.height <= constrainedSize.height
                    && fittingSize.width <= constrainedSize.width {
                    minFontSize = midFontSize
                } else {
                    maxFontSize = midFontSize
                }
            }
    
            return fittingSize
        }
    } 
    

    此函数不会改变标签大小,只影响font 属性。您可以使用返回的尺寸值来调整标签的布局。

    【讨论】:

    • 不错的扩展 ;) 请记住,函数声明中的 var 参数实际上已被弃用,并将在 Swift 3 中删除。
    • 我对这个 sn-p 做了一些改进。现在它已更新为现代 Swift 并可在 iOS 12 上运行。此外,我将 sizeToFit 替换为 sizeThatFits,因此调用此方法不会影响标签框架并且可以很好地处理约束。另外,我添加了方便的返回值,可用于进一步的布局调整。删除了一些多余的调用。
    【解决方案2】:

    如果您想确保标签在宽度和高度方面都适合矩形,您可以在标签上尝试不同的字体大小,看看是否适合。

    这个 sn-p 从 300 pt 开始,并尝试通过减小字体大小使标签适合目标矩形。

    - (void) sizeLabel: (UILabel *) label toRect: (CGRect) labelRect {
    
        // Set the frame of the label to the targeted rectangle
        label.frame = labelRect;
    
        // Try all font sizes from largest to smallest font size
        int fontSize = 300;
        int minFontSize = 5;
    
        // Fit label width wize
        CGSize constraintSize = CGSizeMake(label.frame.size.width, MAXFLOAT);
    
        do {
            // Set current font size
            label.font = [UIFont fontWithName:label.font.fontName size:fontSize];
    
            // Find label size for current font size
            CGRect textRect = [[label text] boundingRectWithSize:constraintSize
                                                         options:NSStringDrawingUsesLineFragmentOrigin
                                                      attributes:@{NSFontAttributeName: label.font}
                                                         context:nil];
    
            CGSize labelSize = textRect.size;
    
            // Done, if created label is within target size
            if( labelSize.height <= label.frame.size.height )
                break;
    
            // Decrease the font size and try again
            fontSize -= 2;
    
        } while (fontSize > minFontSize);
    }
    

    我认为上面解释了发生了什么。更快的实现可以使用缓存和 argarcians 二进制搜索,如下所示

    + (CGFloat) fontSizeForString: (NSString*) s inRect: (CGRect) labelRect  {
        // Cache repeat queries
        static NSMutableDictionary* mutableDict = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            mutableDict = [NSMutableDictionary dictionary];
        });
    
        NSString* key = [NSString stringWithFormat:@"%@_%d_%d", s, (int) labelRect.size.width, (int) labelRect.size.height];
        NSNumber* value = [mutableDict objectForKey:key];
        if (value)
            return value.doubleValue;
    
        // Set the frame of the label to the targeted rectangle
        UILabel* label = [[UILabel alloc] init];
        label.text = s;
        label.frame = labelRect;
    
        // Hopefully between 5 and 300
        CGFloat theSize = (CGFloat) [self binarySearchForFontSizeForLabel:label withMinFontSize:5 withMaxFontSize:300 withSize:label.frame.size];
        [mutableDict setObject:@(theSize) forKey:key];
        return  theSize;
    }
    
    
    + (NSInteger)binarySearchForFontSizeForLabel:(UILabel *)label withMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize withSize:(CGSize)size {
        // If the sizes are incorrect, return 0, or error, or an assertion.
        if (maxFontSize < minFontSize) {
            return maxFontSize;
        }
    
        // Find the middle
        NSInteger fontSize = (minFontSize + maxFontSize) / 2;
        // Create the font
        UIFont *font = [UIFont fontWithName:label.font.fontName size:fontSize];
        // Create a constraint size with max height
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        // Find label size for current font size
        CGRect rect = [label.text boundingRectWithSize:constraintSize
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                            attributes:@{NSFontAttributeName : font}
                                               context:nil];
        CGSize labelSize = rect.size;
    
        // EDIT:  The next block is modified from the original answer posted in SO to consider the width in the decision. This works much better for certain labels that are too thin and were giving bad results.
        if (labelSize.height >= (size.height + 10) && labelSize.width >= (size.width + 10) && labelSize.height <= (size.height) && labelSize.width <= (size.width)) {
            return fontSize;
        } else if (labelSize.height > size.height || labelSize.width > size.width) {
            return [self binarySearchForFontSizeForLabel:label withMinFontSize:minFontSize withMaxFontSize:fontSize - 1 withSize:size];
        } else {
            return [self binarySearchForFontSizeForLabel:label withMinFontSize:fontSize + 1 withMaxFontSize:maxFontSize withSize:size];
        }
    }
    

    【讨论】:

    • 在搜索了几个小时之后,这是唯一对我有用的解决方案。我只是想知道当视图上有 50 到 100 个标签时,while 循环对性能的影响是什么。
    • 我从来没有理由优化它。我不使用它来一遍又一遍地重新计算。我唯一有很多标签大小的地方,我选择了最长的标签文本和大小。
    • @NielsCastle 您的解决方案是否也应用了自动换行技术?我在 agarcian 的回答中写了一个案例。它也满足这种情况吗?
    • 我将它用于短标签。 YMMW。尝试在传入标签上设置 lineBreakMode。
    • 这非常低效,尤其是在调整大小时。
    【解决方案3】:

    @agarcian 的回答很接近,但它对我来说不太有效,正如其他人在评论中提到的那样,它总是返回 0。

    这是我的尝试。

    干杯!

    /**
     * Returns the font size required in order to fit the specified text in the specified area.
     * NB! When drawing, be sure to pass in the same options that we pass to boundingRectWithSize:options:attributes:context:
     * Heavily modified form of: http://stackoverflow.com/a/14662750/1027452
     */
    +(NSInteger)fontSizeForText:(NSString *)text withFont:(UIFont *)font inArea:(CGSize)areaSize minFontSize:(NSInteger)minFontSize maxFontSize:(NSInteger)maxFontSize
    {
    // If the sizes are incorrect, return 0, or error, or an assertion.
        if (maxFontSize < minFontSize) {
            return 0;
        }
    
        // Find the middle
        NSInteger fontSize = (minFontSize + maxFontSize) / 2;
        // Create the font
        UIFont *f = [UIFont fontWithName:font.fontName size:fontSize];
        // Create a constraint size with max height
        CGSize constraintSize = CGSizeMake(areaSize.width, MAXFLOAT);
        // Find label size for current font size
        CGRect rect = [text boundingRectWithSize:constraintSize
                                               options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                            attributes:@{NSFontAttributeName : f}
                                               context:nil];
        CGSize labelSize = rect.size;
    
        if (labelSize.height <= areaSize.height && labelSize.width  <= areaSize.width )
        {
            return fontSize;
        }
        else if (labelSize.height > areaSize.height || labelSize.width > areaSize.width)
        {
            return [self fontSizeForText:text withFont:f inArea:areaSize minFontSize:minFontSize maxFontSize:maxFontSize -1];;
        }
        else
        {
            return [self fontSizeForText:text withFont:f inArea:areaSize minFontSize:minFontSize+1 maxFontSize:maxFontSize];;
        }
    }
    

    【讨论】:

      【解决方案4】:

      基于this 答案的Swift 3“二进制搜索解决方案”略有改进。示例在 UITextView 子类的上下文中:

      func binarySearchOptimalFontSize(min: Int, max: Int) -> Int {
          let middleSize = (min + max) / 2
      
          if min > max {
              return middleSize
          }
      
          let middleFont = UIFont(name: font!.fontName, size: CGFloat(middleSize))!
      
          let attributes = [NSFontAttributeName : middleFont]
          let attributedString = NSAttributedString(string: text, attributes: attributes)
      
          let size = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
          let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
          let textSize = attributedString.boundingRect(with: size, options: options, context: nil)
      
          if textSize.size.equalTo(bounds.size) {
              return middleSize
          } else if (textSize.height > bounds.size.height || textSize.width > bounds.size.width) {
              return binarySearchOptimalFontSize(min: min, max: middleSize - 1)
          } else {
              return binarySearchOptimalFontSize(min: middleSize + 1, max: max)
          }
      }
      

      我希望对某人有所帮助。

      【讨论】:

      • 这不能按预期工作。将greatestFiniteMagnitude 换成宽度,比如CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
      【解决方案5】:

      这是根据@NielsCastle 回答的 Swift 版本,使用二进制搜索

      extension UILabel{
      
          func adjustFontSizeToFitRect(rect : CGRect){
      
              if text == nil{
                  return
              }
      
              frame = rect
      
              let maxFontSize: CGFloat = 100.0
              let minFontSize: CGFloat = 5.0
      
              var q = Int(maxFontSize)
              var p = Int(minFontSize)
      
              let constraintSize = CGSize(width: rect.width, height: CGFloat.max)
      
              while(p <= q){
                  let currentSize = (p + q) / 2
                  font = font.fontWithSize( CGFloat(currentSize) )
                  let text = NSAttributedString(string: self.text!, attributes: [NSFontAttributeName:font])
                  let textRect = text.boundingRectWithSize(constraintSize, options: .UsesLineFragmentOrigin, context: nil)
      
                  let labelSize = textRect.size
      
                  if labelSize.height < frame.height && labelSize.height >= frame.height-10 && labelSize.width < frame.width && labelSize.width >= frame.width-10 {
                      break
                  }else if labelSize.height > frame.height || labelSize.width > frame.width{
                      q = currentSize - 1
                  }else{
                      p = currentSize + 1
                  }
              }
      
          }
      }
      

      用法

      label.adjustFontSizeToFitRect(rect)
      

      通常只是

      label.adjustFontSizeToFitRect(rect.frame)
      

      【讨论】:

      • 很好,谢谢 :) - 我只建议使用 guard statement 替换这个早期返回。
      • @nRewik 很好用。只有当你将UILabel 的高度设为相当高时,字体大小计算就会出错并且超出宽度。将尝试解决此错误并在此处发布。
      【解决方案6】:

      由于我没有使用上述答案找到满足我所有需求的有效解决方案,因此我创建了自己的组件,提供以下功能:FittableFontLabel

      • 在使用多行标签时调整字体以适应高度和宽度
      • 使用单行标签时,调整字体以适应宽度,高度标签会自行调整大小
      • 支持NSAttributedStrings 以及基本字符串
      • 更改标签文本/框架时自动调整大小
      • ...

      如果你们中的任何人感兴趣,它是一个完整的 swift 库,可以使用 CocoaPods:https://github.com/tbaranes/FittableFontLabel

      【讨论】:

        【解决方案7】:

        所有这些都是对原始问题的有趣解决方案,但是它们都缺少一个重要的东西:如果您仅依靠 familyName 来获取 next 字体进行测试,那么您就输了重量信息和可能更高级的属性,如小型大写字母、图形样式等。

        更好的方法是传递字体名称并执行[UIFont fontWithName:someFontName size:someFontSize],传递UIFontDescriptor 对象然后执行 [UIFont fontWithDescriptor:someFontDescriptor size:someFontSize].

        【讨论】:

          【解决方案8】:

          此解决方案(基于this answer)使用自动布局并执行二分搜索以找到最佳字体大小。

          我发现的唯一警告是你不能指定行数(因为 AFAIK 你不能告诉boundingRectWithSize 你想要多少行)。

          AdjustableLabel.h

          #import <UIKit/UIKit.h>
          
          @interface AdjustableLabel : UILabel
          /** 
            If set to YES, font size will be automatically adjusted to frame.
            Note: numberOfLines can't be specified so it will be set to 0.
          */
          @property(nonatomic) BOOL adjustsFontSizeToFitFrame;
          @end
          

          AdjustableLabel.m

          #import "AdjustableLabel.h"
          
          @interface AdjustableLabel ()
          @property(nonatomic) BOOL fontSizeAdjusted;
          @end
          
          // The size found S satisfies: S fits in the frame and and S+DELTA doesn't.
          #define DELTA 0.5
          
          @implementation AdjustableLabel
          
          - (void)setAdjustsFontSizeToFitFrame:(BOOL)adjustsFontSizeToFitFrame
          {
              _adjustsFontSizeToFitFrame = adjustsFontSizeToFitFrame;
          
              if (adjustsFontSizeToFitFrame) {
                  self.numberOfLines = 0; // because boundingRectWithSize works like this was 0 anyway
              }
          }
          
          - (void)layoutSubviews
          {
              [super layoutSubviews];
          
              if (self.adjustsFontSizeToFitFrame && !self.fontSizeAdjusted)
              {
                  self.fontSizeAdjusted = YES; // to avoid recursion, because adjustFontSizeToFrame will trigger this method again
          
                  [self adjustFontSizeToFrame];
              }
          }
          
          - (void) adjustFontSizeToFrame
          {
              UILabel* label = self;
          
              if (label.text.length == 0) return;
          
              // Necessary or single-char texts won't be correctly adjusted
              BOOL checkWidth = label.text.length == 1;
          
              CGSize labelSize = label.frame.size;
          
              // Fit label width-wise
              CGSize constraintSize = CGSizeMake(checkWidth ? MAXFLOAT : labelSize.width, MAXFLOAT);
          
              // Try all font sizes from largest to smallest font size
              CGFloat maxFontSize = 300;
              CGFloat minFontSize = 5;
          
              NSString* text = label.text;
              UIFont* font = label.font;
          
              while (true)
              {
                  // Binary search between min and max
                  CGFloat fontSize = (maxFontSize + minFontSize) / 2;
          
                  // Exit if approached minFontSize enough
                  if (fontSize - minFontSize < DELTA/2) {
                      font = [UIFont fontWithName:font.fontName size:minFontSize];
                      break; // Exit because we reached the biggest font size that fits
                  } else {
                      font = [UIFont fontWithName:font.fontName size:fontSize];
                  }
          
                  // Find label size for current font size
                  CGRect rect = [text boundingRectWithSize:constraintSize
                                                   options:NSStringDrawingUsesLineFragmentOrigin
                                                attributes:@{NSFontAttributeName : font}
                                                   context:nil];
          
                  // Now we discard a half
                  if( rect.size.height <= labelSize.height && (!checkWidth || rect.size.width <= labelSize.width) ) {
                      minFontSize = fontSize; // the best size is in the bigger half
                  } else {
                      maxFontSize = fontSize; // the best size is in the smaller half
                  }
              }
          
              label.font = font;
          }
          
          @end
          

          用法

          AdjustableLabel* label = [[AdjustableLabel alloc] init];
          label.adjustsFontSizeToFitFrame = YES;
          
          // In case you change the font, the size you set doesn't matter
          label.font = [UIFont fontWithName:@"OpenSans-Light" size:20];
          

          【讨论】:

          • 这个。作品。完美。
          • 这非常优雅,而且效果很好。我有一个小的改进,它允许标签文本是一个单词的情况。在这种情况下,您不希望它跨行拆分,所以我在 labelSize 声明之后添加:// If there is only one word, then reduce the height so as to force boundingRectWithSize to fit it on// one line.//if ([label.text componentsSeparatedByString:@" "].count == 1) {`labelSize.height /= 2.0;`}
          【解决方案9】:

          所有的二分搜索都很好,但是使用帧检查停止递归就不那么合乎逻辑了。更好地检查字体大小,因为 UIFont 支持浮动大小,这种字体更合适。 加上使用标签段落样式精确计算大小。

          如果有人感兴趣,可以看下面的代码:

          static UIFont * ___suitableFontInRangePrivate(const CGSize labelSize,
                                                      NSParagraphStyle * paragraphStyle,
                                                      NSString * fontName,
                                                      NSString * text,
                                                      const CGFloat minSize,
                                                      const CGFloat maxSize)
          {
              // Font size in range, middle size between max & min.
              const CGFloat currentSize = minSize + ((maxSize - minSize) / 2);
          
              // Font with middle size.
              UIFont * currentFont = [UIFont fontWithName:fontName size:currentSize];
          
              // Calculate text height.
              const CGFloat textHeight = [text boundingRectWithSize:CGSizeMake(labelSize.width, CGFLOAT_MAX)
                                                          options:NSStringDrawingUsesLineFragmentOrigin
                                                      attributes:@{ NSFontAttributeName : currentFont, NSParagraphStyleAttributeName : paragraphStyle }
                                                          context:nil].size.height;
              CGFloat min, max;
              if (textHeight > labelSize.height)
              {
                  // Take left range part.
                  min = minSize;
                  max = currentSize;
              }
              else
              {
                  // Take right range part.
                  min = currentSize;
                  max = maxSize;
              }
          
              // If font size in int range [0.0; 2.0] - got it, othervice continue search.
              return ((max - min) <= 2.0) ? currentFont : ___suitableFontInRangePrivate(labelSize, paragraphStyle, fontName, text, min, max);
          }
          
          void UILabelAdjustsFontSizeToFrame(UILabel * label)
          {
              if (!label) return;
          
              NSString * text = [label text];
          
              __block NSParagraphStyle * style = nil;
              [[label attributedText] enumerateAttributesInRange:NSMakeRange(0, [text length])
                                                      options:(NSAttributedStringEnumerationOptions)0
                                                      usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop){
                                                          id paragraphStyle = [attrs objectForKey:@"NSParagraphStyle"];
                                                          if (paragraphStyle) style = [paragraphStyle retain];
                                                      }];
          
              if (!style)
              {
                  NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
                  if (!paragraphStyle) paragraphStyle = [[NSMutableParagraphStyle alloc] init];
                  if (paragraphStyle)
                  {
                      [paragraphStyle setLineBreakMode:[label lineBreakMode]];
                      [paragraphStyle setAlignment:[label textAlignment]];
                  }
                  style = paragraphStyle;
              }
          
              UIFont * suitableFont = ___suitableFontInRangePrivate([label frame].size, style, [[label font] fontName], text, 0, 500);
              [label setFont:suitableFont];
              [style release];
          }
          

          【讨论】:

            【解决方案10】:

            我根据@agarcian 的回答为 UILabel 创建了类别。但是我根据屏幕上绘制文本所需的正方形来计算字体大小。该方法无需循环,一次迭代即可完成计算。

            这里是 .h 文件:

            //  UILabel+Extended.h
            //  Created by Firuz on 16/08/14.
            //  Copyright (c) 2014. All rights reserved.
            
            #import <UIKit/UIKit.h>
            
            @interface UILabel (Extended)
            
            /** This method calculate the optimal font size for current number of lines in UILable. Mus be called after drawing UILabel view */
            - (NSInteger)fontSizeWithMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize;
            
            @end
            

            这里是 .m 文件:

            //  UILabel+Extended.m
            //  Created by Firuz on 16/08/14.
            //  Copyright (c) 2014. All rights reserved.
            
            #import "UILabel+Extended.h"
            
            @implementation UILabel (Extended)
            
            - (NSInteger)fontSizeWithMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize
            {
                if (maxFontSize < minFontSize) {
                    return 0;
                }
            
                UIFont *font = [UIFont fontWithName:self.font.fontName size:maxFontSize];
            
                CGFloat lineHeight = [font lineHeight];
            
                CGSize constraintSize = CGSizeMake(MAXFLOAT, lineHeight);
            
                CGRect rect = [self.text boundingRectWithSize:constraintSize
                                                       options:NSStringDrawingUsesLineFragmentOrigin
                                                    attributes:@{NSFontAttributeName : font}
                                                       context:nil];
            
                CGFloat labelSqr = self.frame.size.width * self.frame.size.height;
                CGFloat stringSqr = rect.size.width/self.frame.size.width * (lineHeight + font.pointSize) * self.frame.size.width;
            
                CGFloat multiplyer = labelSqr/stringSqr;
            
                if (multiplyer < 1) {
                    if (minFontSize < maxFontSize*multiplyer) {
                        return maxFontSize * multiplyer;
                    } else {
                        return minFontSize;
                    }
                }
                return maxFontSize;
            }
            
            @end
            

            【讨论】:

              【解决方案11】:

              我发现 Niels 的答案是这个问题的最佳答案。但是,我有一个 UIView,它可以有 100 个标签,我需要在其中放置文本,所以这个过程非常低效,我可以感受到性能的影响。

              这是他的代码修改为使用二进制搜索,而不是线性搜索。现在它的工作效率很高。

              - (NSInteger)binarySearchForFontSizeForLabel:(UILabel *)label withMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize withSize:(CGSize)size {
                  // If the sizes are incorrect, return 0, or error, or an assertion.
                  if (maxFontSize < minFontSize) {
                      return 0;
                  }
              
                  // Find the middle
                  NSInteger fontSize = (minFontSize + maxFontSize) / 2;
                  // Create the font
                  UIFont *font = [UIFont fontWithName:label.font.fontName size:fontSize];
                  // Create a constraint size with max height
                  CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
                  // Find label size for current font size
                  CGRect rect = [label.text boundingRectWithSize:constraintSize
                                                         options:NSStringDrawingUsesLineFragmentOrigin
                                                      attributes:@{NSFontAttributeName : font}
                                                         context:nil];
                  CGSize labelSize = rect.size;
              
                  // EDIT:  The next block is modified from the original answer posted in SO to consider the width in the decision. This works much better for certain labels that are too thin and were giving bad results.
                  if (labelSize.height >= (size.height + 10) && labelSize.width >= (size.width + 10) && labelSize.height <= (size.height) && labelSize.width <= (size.width)) {
                      return fontSize;
                  } else if (labelSize.height > size.height || labelSize.width > size.width) {
                      return [self binarySearchForFontSizeForLabel:label withMinFontSize:minFontSize withMaxFontSize:fontSize - 1 withSize:size];
                  } else {
                      return [self binarySearchForFontSizeForLabel:label withMinFontSize:fontSize + 1 withMaxFontSize:maxFontSize withSize:size];
                  }
              }
              
              - (void)sizeBinaryLabel:(UILabel *)label toRect:(CGRect)labelRect {
              
                  // Set the frame of the label to the targeted rectangle
                  label.frame = labelRect;
              
                  // Try all font sizes from largest to smallest font
                  int maxFontSize = 300;
                  int minFontSize = 5;
              
                  NSInteger size = [self binarySearchForFontSizeForLabel:label withMinFontSize:minFontSize withMaxFontSize:maxFontSize withSize:label.frame.size];
              
                  label.font = [UIFont fontWithName:label.font.fontName size:size];
              
              }
              

              感谢https://gist.github.com/988219

              【讨论】:

              • +1 - 我正要写一个二进制搜索解决方案,然后向下滚动,发现二进制解决方案已经发布了!对于大多数情况,这绝对是一个更好的解决方案。很棒的龙舌兰。
              • 谢谢帕万。这就是 SO 的美妙之处。合作将为我们节省大量的开发时间:-)
              • 我只是在答案中添加了一个编辑,因为在前面的代码中,一些太薄的标签没有完全在标签内显示文本。代码中的更改不仅包括检查高度,还包括检查宽度。
              • 嗯,@agarcian 的代码对我来说总是为 0。 maxFontSize 和 minFontSize 在没有达到第一个 if-then 的情况下变得相等。即使在一个非常基本的测试项目中。 Niels 的代码运行良好,尽管速度较慢。
              • 对于非常长的文本和非常短的文本来说非常不精确。
              【解决方案12】:

              如果有人正在寻找 MonoTouch/Xamarin.iOS 实现,就像我一样......你去吧:

              private int BinarySearchForFontSizeForText(NSString text, int minFontSize, int maxFontSize, SizeF size)
              {
                  if (maxFontSize < minFontSize) 
                      return minFontSize;
              
                  int fontSize = (minFontSize + maxFontSize) / 2;
                  UIFont font = UIFont.BoldSystemFontOfSize(fontSize);
              
                  var constraintSize = new SizeF(size.Width, float.MaxValue);
                  SizeF labelSize = text.StringSize(font, constraintSize, UILineBreakMode.WordWrap);
              
                  if (labelSize.Height >= size.Height + 10 && labelSize.Width >= size.Width + 10 && labelSize.Height <= size.Height && labelSize.Width <= size.Width)
                      return fontSize;
                  else if (labelSize.Height > size.Height || labelSize.Width > size.Width) 
                      return BinarySearchForFontSizeForText(text, minFontSize, fontSize - 1, size);
                  else 
                      return BinarySearchForFontSizeForText(text, fontSize + 1, maxFontSize, size);
              }
              
              private void SizeLabelToRect(UILabel label, RectangleF labelRect)
              {
                  label.Frame = labelRect;
              
                  int maxFontSize = 300;
                  int minFontSize = 5;
                  int size = BinarySearchForFontSizeForText(new NSString(label.Text), minFontSize, maxFontSize, label.Frame.Size);
              
                  label.Font = UIFont.SystemFontOfSize(size);
              }
              

              这是 agarcian 的代码从 Objective-C 到 C# 的翻译,稍作修改:由于返回结果始终为 0 (see the comment of borked),因此我返回计算出的 minFontSize,从而得到正确的字体大小。

              【讨论】:

              • 非常感谢您的“小修改”。
              【解决方案13】:

              Niels Castle 代码工作查找。

              这是相同的想法,但实现不同。
              我的解决方案更精确,但 CPU 密集度更高。

              将此函数添加到继承 UILabel 的类中。

              -(void)fitCurrentFrame{
              
                  CGSize iHave = self.frame.size;
              
                  BOOL isContained = NO;
                  do{
                      CGSize iWant = [self.text sizeWithFont:self.font];
                      if(iWant.width > iHave.width || iWant.height > iHave.height){
                          self.font = [UIFont fontWithName:self.font.fontName size:self.font.pointSize - 0.1];
                          isContained = NO;
                      }else{
                          isContained = YES;
                      }
              
                  }while (isContained == NO);
              }
              

              【讨论】:

                【解决方案14】:

                还可以设置myLabel.numberOfLines = 10 或任何你想要的最大行数。

                【讨论】:

                • 或者简单地 0 表示无限行数
                • ^这家伙知道他在说什么
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-02-13
                • 1970-01-01
                • 2015-05-07
                • 2018-10-16
                • 2011-02-06
                • 1970-01-01
                相关资源
                最近更新 更多