如何查找UILabel的实际行数?

时间:2015-01-23 11:18:13

标签: ios uilabel

在使用UILabeltext初始化font之后,如何找到实际行数?我已将其numberOfLines属性设置为0,因此它会扩展到需要很多行。但是,在设置text之后,我怎样才能知道最终获得了多少行?

我发现了类似的问题,但似乎没有一个提供简洁的答案,而且在我看来,在boundingRectWithSizesizeWithFont玩杂耍时,一定要轻松获得它, ...

16 个答案:

答案 0 :(得分:51)

这些都不适合我。下面有一个,

Swift 4.2:

extension UILabel {
    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }    
}

Swift 4 / 4.1:

extension UILabel {

    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }

}

斯威夫特3:

extension UILabel {

    func calculateMaxLines() -> Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }

}

答案 1 :(得分:45)

首先在UILabel中设置文本

第一个选项:

首先根据字体计算文本的高度:

NSInteger lineCount = 0;
CGSize labelSize = (CGSize){yourLabel.frame.size.width, MAXFLOAT};
CGRect requiredSize = [self boundingRectWithSize:labelSize  options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: yourLabel.font} context:nil];

现在计算行数:

int charSize = lroundf(yourLabel.font.lineHeight);
int rHeight = lroundf(requiredSize.height);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);

第二个选项:

 NSInteger lineCount = 0;
 CGSize textSize = CGSizeMake(yourLabel.frame.size.width, MAXFLOAT);
 int rHeight = lroundf([yourLabel sizeThatFits:textSize].height);
 int charSize = lroundf(yourLabel.font.lineHeight);
 lineCount = rHeight/charSize;
 NSLog(@"No of lines: %i",lineCount);

答案 2 :(得分:37)

Swift 5(IOS 12.2)

  

获取标签在不截断的情况下呈现文本所需的最大行数。

extension UILabel {
    var maxNumberOfLines: Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
        let text = (self.text ?? "") as NSString
        let textHeight = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height
        let lineHeight = font.lineHeight
        return Int(ceil(textHeight / lineHeight))
    }
}
  

获取最大行数可以在具有约束边界的标签中显示。在将文本分配给标签后使用此属性。

extension UILabel {
    var numberOfVisibleLines: Int {
        let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
        let textHeight = sizeThatFits(maxSize).height
        let lineHeight = font.lineHeight
        return Int(ceil(textHeight / lineHeight))
    }
}

<强> 用法

print(yourLabel.maxNumberOfLines)
print(yourLabel.numberOfVisibleLines)

答案 3 :(得分:16)

以下是@Paresh解决方案的 swift版本

func lines(label: UILabel) -> Int {
    let textSize = CGSize(width: label.frame.size.width, height: CGFloat(Float.infinity))
    let rHeight = lroundf(Float(label.sizeThatFits(textSize).height))
    let charSize = lroundf(Float(label.font.lineHeight))
    let lineCount = rHeight/charSize
    return lineCount
}
编辑:我不知道为什么,但代码返回的行数比实际行数多2行,对于我的解决方案,我只是在返回lineCount之前减去它们。

答案 4 :(得分:10)

此处的其他答案在numberOfLines设置为0以外的值时不会尊重UILabel属性。

这是您可以添加到类别或子类的另一个选项:

- (NSUInteger)lineCount
{
    CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    return MAX((int)(size.height / self.font.lineHeight), 0);
}

一些注意事项:

  • 我在带有属性文本的UILabel上使用它,而没有实际设置font属性,并且它工作正常。如果您在attributedText中使用多种字体,显然会遇到问题。
  • 如果你将UILabel子类化为自定义边缘插入(例如通过覆盖drawTextInRect:,这是我找到here的一个巧妙的技巧,那么你必须记住采取这些插入在计算上面的size时会考虑到这一点。例如:CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)

答案 5 :(得分:8)

这是Swift3代码 在这里你可以使用(MAXFLOAT)定义Int值并获得文本大小的高度,使用该高度可以获得UILabel的总高度,并通过按字符大小划分总高度,可以获得UILabel的实际行数。 / p>

var lineCount: Int = 0
var textSize = CGSize(width: CGFloat(yourLabel.frame.size.width), height: CGFloat(MAXFLOAT))
var rHeight: Int = lroundf(yourLabel.sizeThatFits(textSize).height)
var charSize: Int = lroundf(yourLabel.font.leading)
lineCount = rHeight / charSize
print("No of lines: \(lineCount)")

答案 6 :(得分:4)

按照@Prince的回答,我现在在UILabel上实现了一个类别,如下所示(注意我在他的回答中纠正了一些不会让代码编译的错误语法错误):

的UILabel + Util.h

#import <UIKit/UIKit.h>

@interface UILabel (Util)
- (NSInteger)lineCount;
@end

的UILabel +的Util。,

#import "UILabel+Util.h"

@implementation UILabel (Util)

- (NSInteger)lineCount
{
    // Calculate height text according to font
    NSInteger lineCount = 0;
    CGSize labelSize = (CGSize){self.frame.size.width, FLT_MAX};
    CGRect requiredSize = [self.text boundingRectWithSize:labelSize  options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: self.font} context:nil];

    // Calculate number of lines
    int charSize = self.font.leading;
    int rHeight = requiredSize.size.height;
    lineCount = rHeight/charSize;

    return lineCount;
}

@end

答案 7 :(得分:4)

您可以在自定义标签中找到可用的总行数 请检查此代码......

chartArea

答案 8 :(得分:3)

似乎官方开发人员网站在Objc中提到了一种解决方案Counting Lines of Text。但是,它假定您对配置了布局管理器,文本存储和文本容器的文本视图有引用。不幸的是,UILabel并没有向我们公开这些内容,因此我们需要使用与UILabel相同的配置来创建它们。

我将Objc代码翻译如下。对我来说似乎很好。

extension UILabel {
    var actualNumberOfLines: Int {
        let textStorage = NSTextStorage(attributedString: self.attributedText!)
        let layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        let textContainer = NSTextContainer(size: self.bounds.size)
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = self.lineBreakMode
        layoutManager.addTextContainer(textContainer)

        let numberOfGlyphs = layoutManager.numberOfGlyphs
        var numberOfLines = 0, index = 0, lineRange = NSMakeRange(0, 1)

        while index < numberOfGlyphs {
            layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
            index = NSMaxRange(lineRange)
            numberOfLines += 1
        }
        return numberOfLines
    }
}

答案 9 :(得分:3)

Swift 5.2

对我来说主要的工作是调用 label.layoutIfNeeded(),因为我使用的是autoLayout,否则它将不起作用。

func actualNumberOfLines(label: UILabel) -> Int {
        // You have to call layoutIfNeeded() if you are using autoLayout
        label.layoutIfNeeded()

        let myText = label.text! as NSString

        let rect = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude)
        let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: label.font as Any], context: nil)

        return Int(ceil(CGFloat(labelSize.height) / label.font.lineHeight))
    }

致谢:https://gist.github.com/fuxingloh/ccf26bb68f4b8e6cfd02,该版本以较早的迅捷版本提供了解决方案,并提到了layoutIfNeeded()的重要性。

答案 10 :(得分:0)

Xamarin.iOS

感谢上面每个人提供的答案。

这将获得可见线的数量。

$0.hidden = Condition.function(["placeOfLiving"])
   { form in
      if let row = form.rowBy(tag: "placeOfLiving") as? ActionSheetRow<String> {
          return section.value == "Antartica"
       }
       return false
   }

这将获取文本在屏幕上占据的实际行数。

public static int VisibleLineCount(this UILabel label)
{
    var textSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
    nfloat rHeight = label.SizeThatFits(textSize).Height;
    nfloat charSize = label.Font.LineHeight;
    return Convert.ToInt32(rHeight / charSize);
}

我发现对我的用例有用的辅助方法。

public static int LineCount(this UILabel label)
{
    var maxSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
    var charSize = label.Font.LineHeight;
    var text = (label.Text ?? "").ToNSString();
    var textSize = text.GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, new UIStringAttributes() { Font = label.Font }, null);
    return Convert.ToInt32(textSize.Height / charSize);
}

要获得更准确的行数:

  • 使用public static bool IsTextTruncated(this UILabel label) { if (label.Lines == 0) { return false; } return (label.LineCount() > label.Lines); } 代替font.lineHeight
  • round()除后的行数

答案 11 :(得分:0)

let l = UILabel()
l.numberOfLines = 0
l.layer.frame.size.width = self.view.frame.width - 40 /*padding(20 + 20)*/

l.font = UIFont(name: "BwModelica-Bold", size: 16.0)

l.text = "Random Any length Text!!"

let noOfLines = ceil(l.intrinsicContentSize.width) / l.frame.width)

let lbl_height = noOfLines * l.intrinsicContentSize.height

这将是您的Label的确切动态高度和行数。编码愉快!

答案 12 :(得分:0)

请注意,@ kurt-j的答案并不总是有效。在某些情况下,您将必须手动提供标签的宽度。由于存在这些情况,因此即使您最终不使用宽度参数也是一个好主意。

Swift 4.2:

extension UILabel {
    func calculateMaxLines(actualWidth: CGFloat?) -> Int {
        var width = frame.size.width
        if let actualWidth = actualWidth {
            width = actualWidth
        }
        let maxSize = CGSize(width: width, height: CGFloat(Float.infinity))
        let charSize = font.lineHeight
        let text = (self.text ?? "") as NSString
        let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        let linesRoundedUp = Int(ceil(textSize.height/charSize)) 
        return linesRoundedUp
    }    
}

答案 13 :(得分:0)

⚠️ 也不是 lineHeight,也不是 leading 本身就足够了。

font.lineHeight 是字形的高度,它从 descender(最低字形的底部)到 ascender(最高字形的顶部)。另请注意,可以覆盖属性字符串的 lineHeightfont.leading 是 (!) 行之间的额外(但可能是负数)空间(请参阅文档)。如果您使用系统字体,几乎每个磅值都会得到不同的行距。

所以例如5 行标签的高度由 5 lineHeight 和 4 leading 组成(但前导值通常小到足以使上述解决方案起作用,直到您开始使用多行。

所以正确的(伪)公式应该是:

(frame.size.height + font.leading) / (font.lineHeight + font.leading)
<块引用>

此外,如果属性字符串的附件太大(高于字体的 ascender),那么它也会改变该行的行高。< /p>

答案 14 :(得分:0)

Swift 5.4 Fernando Cardenas 的重构方案为 UILabel 扩展

private extension UILabel {
    var actualNumberOfLines: Int {
        guard let text = self.text else {
            return 0
        }
        layoutIfNeeded()
        let rect = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
        let labelSize = text.boundingRect(
            with: rect,
            options: .usesLineFragmentOrigin,
            attributes: [NSAttributedString.Key.font: font as Any],
            context: nil)
        return Int(ceil(CGFloat(labelSize.height) / font.lineHeight))
    }
}

答案 15 :(得分:-1)

Xamarin iOS

label.Text = text;

var lineCount = 0;
var textSize = new CGSize(label.Frame.Size.Width, float.MaxValue);
var height = label.SizeThatFits(textSize).Height;
var fontHeight = label.Font.LineHeight;

lineCount = Convert.ToInt32(height / fontHeight);