【问题标题】:Calculating UILabel Text Size计算 UILabel 文本大小
【发布时间】:2013-10-08 08:34:33
【问题描述】:

我正在以编程方式绘制UILabels。他们从数据库中获取大小。所以我不能只使用sizeToFit。我已经实现了一个以通过率重绘UILabels 的函数。所以我只需要找到UILabel 中的文本,从我的角度来看,这需要最大比率来重绘UILabels。 所以最后我需要做这样的事情:

    double ratio = 1.00;
    for (UILabel* labels in sec.subviews) {

        float widthLabel = labels.frame.size.width;
        float heightLabel = labels.frame.size.height;
        float heightText = //get the text height here
        float widthText = //get the text width here
        if (widthLabel < widthText) {
            ratio = MAX(widthText/widthLabel,ratio);
        }
        if (heightLabel < heightText) {
            ratio = MAX(heightText/heightLabel, ratio);
        }
    }
    //redraw UILabels with the given ratio here

那么我怎样才能获得文本的高度和宽度大小,因为我的一些文本不适合标签我不能简单地使用标签边界?我正在使用 Xcode 5 和 iOS 7。

【问题讨论】:

    标签: ios objective-c uilabel frame


    【解决方案1】:

    所有 [NSString sizeWithFont...] 方法在 iOS 7 中都已弃用。请改用它。

    CGRect labelRect = [text
                        boundingRectWithSize:labelSize
                        options:NSStringDrawingUsesLineFragmentOrigin
                        attributes:@{
                         NSFontAttributeName : [UIFont systemFontOfSize:14]
                        }
                        context:nil];
    

    另见https://developer.apple.com/documentation/foundation/nsstring/1619914-sizewithfont

    更新 - boundingRectWithSize 输出示例

    根据您的评论,我做了一个简单的测试。代码和输出如下。

    // code to generate a bounding rect for text at various font sizes
    NSString *text = @"This is a long sentence. Wonder how much space is needed?";
    for (NSNumber *n in @[@(12.0f), @(14.0f), @(18.0f)]) {
        CGFloat fontSize = [n floatValue];
        CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
                                      options:NSStringDrawingUsesLineFragmentOrigin
                                   attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                                      context:nil];
        NSLog(@"fontSize = %f\tbounds = (%f x %f)",
              fontSize,
              r.size.width,
              r.size.height);
    }
    

    这会产生以下输出(请注意,随着字体大小变大,边界会按预期变化):

    fontSize = 12.000000    bounds = (181.152008 x 28.632000)
    fontSize = 14.000000    bounds = (182.251999 x 50.105999)
    fontSize = 18.000000    bounds = (194.039993 x 64.421997)
    

    【讨论】:

    • 有没有办法获取 UILabel 文本的字体大小或者我必须对其进行硬编码?
    • 不确定我是否理解您的问题。 label.font.pointSize 将为您提供标签的字体大小。如果您要问如何知道在没有标签对象的情况下计算边界时要使用什么字体大小,那么是的,您必须以与为标签设置字体相同的方式编写代码(即,无论您想要您的应用程序) .
    • 您的解决方案并没有真正起作用,当我将UIFont 尺寸设为 18 时,我的文本尺寸为“{49.337997, 42.947998}”。当我将其设为 14 时,结果为“{55.244003, 50.105999}”,如果我将其设为 12,则结果为“{47.736, 42.947998}”。所以由于某种原因,它没有给出准确的尺寸。
    • 另外,如果我制作 label.font 那么我会得到 {46.390137, 51.089844}。顺便说一下,当前标签的大小为 {53,53} 会溢出,我需要得到类似 {75,75} 的东西才能使比率准确。
    • 我不知道您在代码中还做了什么。此功能确实为您提供了显示具有给定属性的文本所需的矩形。我将它广泛用于此目的。这不是真正的“我的解决方案”,这是 Apple 定义的方法。我刚刚提醒过你。
    【解决方案2】:

    Length 获取字符数。如果要获取文字的宽度:

    Objective-C

    CGSize textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[label font]}];
    

    斯威夫特 4

    let size = label.text?.size(withAttributes: [.font: label.font]) ?? .zero
    

    这会让你得到大小。并且可以比较每个标签的textSize.width

    【讨论】:

    • 这应该是最好的答案了。
    • 请注意,这不适用于多行 UILabel
    • @DaronTancharoen 你有多行的解决方案吗?我以前不需要它,所以如果您找到解决方案,我们可以编辑答案。
    • 考虑到换行符也应该进行一些大小计算。
    • @DaronTancharoen 请参阅下面的多行标签答案。
    【解决方案3】:

    另一种我还没有提到的简单方法:

    CGSize textSize = [label intrinsicContentSize];
    

    (当然,这只有在您设置了标签的文本和字体后才能正常工作。)

    【讨论】:

    • 这对我来说是正确的答案。 boundingRectWithSize 有时会提供不正确的尺寸。
    • 迄今为止的最佳答案
    【解决方案4】:

    这是一个 swift 变体。

    let font = UIFont(name: "HelveticaNeue", size: 25)!
    let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"
    
    let textString = text as NSString
    
    let textAttributes = [NSFontAttributeName: font]
    
    textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
    

    【讨论】:

    • 谢谢,这是我一直在寻找的全方位解决方案。它甚至不需要 UILabel。它可以与任何字符串一起使用。
    • 似乎不适用于 UILabel。所以我使用了 UITextView,它成功了。
    • 我在从 TableViewCell 中的自动调整 UITextView 获得一致的行数时遇到了一些问题,这是唯一有效的方法。谢谢!
    【解决方案5】:

    小伙子们,如果你像我一样使用,boundingRectWithSize[UIFont systemFontOFSize:14]

    如果您的字符串是两行长,则返回的矩形高度大约是 33,4 点。

    不要像我一样犯错误,将其转换为int,因为 33,4 变成 33,33 点高度标签从两到一行传递!

    【讨论】:

    • 我建议永远不要使用 int 来确定屏幕尺寸或位置,只要坚持使用 CGFloat
    • @ErikvanderNeut 完全同意。使用 Swift 会迫使你这样做!
    • 在swift中你仍然可以使用CGFloat(例如var x:CGFloat = 14
    【解决方案6】:

    问题

    CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                                  context:nil];
    

    boundingRectWithSize,它决定了CGRect可以有的最大值。

    我对这个问题的解决方案是检查它是否超过,如果没有,那么文本可以适合标签。我通过使用循环来做到这一点。

    NSString *text = @"This is a long sentence. Wonder how much space is needed?";
    CGFloat width = 100;
    CGFloat height = 100;
    bool sizeFound = false;
    while (!sizeFound) {
        NSLog(@"Begin loop");
        CGFloat fontSize = 14;
        CGFloat previousSize = 0.0;
        CGFloat currSize = 0.0;
        for (float fSize = fontSize; fSize < fontSize+6; fSize++) {
            CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fSize]}
                                          context:nil];
            currSize =r.size.width*r.size.height;
            if (previousSize >= currSize) {
                width = width*11/10;
                height = height*11/10;
                fSize = fontSize+10;
            }
            else {
                previousSize = currSize;
            }
            NSLog(@"fontSize = %f\tbounds = (%f x %f) = %f",
                  fSize,
                  r.size.width,
                  r.size.height,r.size.width*r.size.height);
        }
        if (previousSize == currSize) {
            sizeFound = true;
        }
    
    }
    NSLog(@"Size found with width %f and height %f", width, height);
    

    每次迭代后,高度和宽度的大小都会增加其值的 10%。

    之所以选择 6,是因为我不想标签太糊。

    对于不使用循环的解决方案:

    NSString *text = @"This is a long sentence. Wonder how much space is needed?";
    CGFloat width = 100;
    CGFloat height = 100;
    
    CGFloat currentFontSize = 12;
    CGRect r1 = [text boundingRectWithSize:CGSizeMake(width, height)
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
                                  context:nil];
    
    CGRect r2 = [text boundingRectWithSize:CGSizeMake(width, height)
                                   options:NSStringDrawingUsesFontLeading
                                attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
                                   context:nil];
    
    CGFloat firstVal =r1.size.width*r1.size.height;
    CGFloat secondVal =r2.size.width*r2.size.height;
    
    NSLog(@"First val %f and second val is %f", firstVal, secondVal);
    
    if (secondVal > firstVal) {
        float initRat = secondVal/firstVal;
    
        float ratioToBeMult = sqrtf(initRat);
    
        width *= ratioToBeMult;
        height *= ratioToBeMult;
    }
    
    NSLog(@"Final width %f and height %f", width, height);
    
    //for verifying
    for (NSNumber *n in @[@(12.0f), @(14.0f), @(17.0f)]) {
        CGFloat fontSize = [n floatValue];
        CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
                                      options:NSStringDrawingUsesLineFragmentOrigin
                                   attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
                                      context:nil];
        NSLog(@"fontSize = %f\tbounds = (%f x %f) = %f",
              fontSize,
              r.size.width,
              r.size.height,r.size.width*r.size.height);
        firstVal =r.size.width*r.size.height;
    }
    

    最后一个循环证明更大的字体可以产生更大的结果。

    【讨论】:

      【解决方案7】:

      使用多行标签 (Swift 4) 的解决方案,从固定宽度计算高度:

      let label = UILabel(frame: .zero)
      label.numberOfLines = 0 // multiline
      label.font = UIFont.systemFont(ofSize: UIFont.labelFontSize) // your font
      label.preferredMaxLayoutWidth = width // max width
      label.text = "This is a sample text.\nWith a second line!" // the text to display in the label
      
      let height = label.intrinsicContentSize.height
      

      【讨论】:

      • 这实际上是很多用例的更好解决方案。
      【解决方案8】:

      通过这行代码我们可以得到标签上文字的大小。

      let str = "Sample text"
      let size = str.sizeWithAttributes([NSFontAttributeName:UIFont.systemFontOfSize(17.0)])
      

      所以,我们可以同时使用宽度和高度。

      【讨论】:

      • 您需要提供您的应用中使用的字体
      • 我使用了系统字体 16,但我需要在代码中设置字体 26 以获得宽度
      • 我的文字是“UNKNOWN”,但是设置字体16 -> 得到68.5宽度,所以只能显示“UN” 当设置字体26时,它会显示完整的“UNKNOWN”
      【解决方案9】:

      msgStr 字符串获取大小:

      let msgStr:NSString = Data["msg"]! as NSString
      let messageSize = msgStr.boundingRect(with: CGSize(width: ChatTable.frame.width-116, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont(name: "Montserrat-Light", size: 14)!], context: nil).size
      

      【讨论】:

        【解决方案10】:

        Swift 3.0

        func getLabelHeight() -> CGFloat {
            let font = UIFont(name: "OpenSans", size: 15)!
            let textString = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." as NSString
        
            let textAttributes = [NSFontAttributeName: font]
        
            let rect = textString.boundingRect(with: CGSize(width: 320, height: 2000), options: .usesLineFragmentOrigin, attributes: textAttributes, context: nil)
            return rect.size.height
        }
        

        【讨论】:

          【解决方案11】:

          这是一个非常丑陋的混乱,因为如果你在设置 UILabel 字体之后使用属性字符串设置它,它会破坏属性文本中的字体信息,你必须根据文本+字体属性进行计算

          有什么好调的

              CGFloat promptLabelMaxWidth = self.promptLabel.frame.size.width;
              NSAttributedString *attributedText = self.promptLabel.attributedText;
              assert(attributedText);
              CGRect rect = [attributedText boundingRectWithSize:(CGSize){promptLabelMaxWidth, CGFLOAT_MAX} options: NSStringDrawingUsesLineFragmentOrigin context:nil];
              NSString *text = self.promptLabel.text;
              UIFont *font = self.promptLabel.font;
              if (font) {
                  CGRect r = [text boundingRectWithSize: CGSizeMake(promptLabelMaxWidth, CGFLOAT_MAX)
                                                    options:NSStringDrawingUsesLineFragmentOrigin
                                                 attributes:@{NSFontAttributeName: font}
                                                    context:nil];
                  if (r.size.height > rect.size.height) {
                      rect = r;
                  }
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-10-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-15
            • 2015-08-07
            • 1970-01-01
            • 2014-05-04
            相关资源
            最近更新 更多