如何找到UILabel的实际行数?


69

用a和a初始化后,如何找到a的实际行数?我将其属性设置为,因此它将扩展为需要很多行。但是,然后,如何确定设置后最终得到的行数呢?UILabeltextfontnumberOfLines0text

我发现了类似的问题,但似乎没有一个简单的答案,而且在我看来,必须很容易就可以轻松获得它,而不必在处理boundingRectWithSizeor或sizeWithFont...时产生任何开销。

Answers:


58

首先在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);

5
int charSize = lroundf(yourLabel.font.lineHeight);
Brooks Hanes

1
我认为您应该在除以rHeight / charSize之后四舍五入,将rHeight和charSize四舍五入可能会导致一行丢失,在我的情况下。
光'16

2
就像提到的@BrooksHanes一样-领先与lineHeight不同The leading value represents additional space between lines of text and is measured in points.developer.apple.com/reference/uikit/uifont/1619026-leading)。
克里斯·普林斯

还有-boundingRectWithSize是NSString的一种方法。
克里斯·普林斯

lineHeight确实有效,leading但无效(至少对我而言)。更新了答案
yonix

72

这些都不对我有用。不到一个,

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

斯威夫特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
    }

}

行应四舍五入。let lines = textSize.height / charSize let linesRounded = Int(ceil(lines))返回linesRounded
Tommy Sadiq Hinrichsen

@TommySadiqHinrichsen我认为,textSize.height / charSize应该不会等于确切的整数。您有没有的情况吗?
Kurt J

使用线间距时。我可以看到您的观点,但我认为它更可靠,因为我们都知道浮点数有时会发生奇怪的事情。
Tommy Sadiq Hinrichsen

是的,但是我认为这仅适用于在计算boudingRect时指定了段落样式。我想我可以更改它,因为我认为它不会造成任何伤害。
Kurt J

1
frame.size.width有时返回0,并且给出错误的maxSize并基于该textSize。以我UIScreen.main.bounds.width为例,将width设置为maxSize解决了问题
lmboom

57

迅捷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)

5
它为我提供了另一行,可见行数为5,但您的方法返回了
6。– Markicevic

1
let zone = CGSize(width: intrinsicContentSize.width, height: CGFloat(MAXFLOAT)) let fittingHeight = Float(self.sizeThatFits(zone).height) return lroundf(fittingHeight / Float(font.lineHeight)) 为我计算正确的线
Azules

这是一个好的答案,但是如果您使用自动换行,有时会给您错误的答案。@sam的答案在下面给出了最佳结果。
罗伯·施密德

20

这是@Paresh解决方案的快速版本

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之前减去了它们。


10

这里的其他答案不尊重numberOfLines的财产UILabel设置为0以外的其他。

您可以在类别或子类中添加另一个选项:

- (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具有自定义边缘插图(例如,通过overriding drawTextInRect:,这是我在这里找到的巧妙技巧),那么在计算size上述值时必须记住要考虑这些插图。例如:CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)

9

这是Swift3代码 ,您可以在其中定义Int值,并使用(MAXFLOAT)获得文本大小的高度,并使用该高度可以获取UILabel的总高度,并通过按字符大小指定总高度可以得到实际的行UILabel的数量。

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

尽管此代码段是受欢迎的,并且可能会提供一些帮助,但是如果它包含有关如何以及为什么可以解决此问题的说明,则可以大大改善。请记住,您将来会为读者回答问题,而不仅仅是现在问的人!请编辑您的答案以添加解释,并指出适用的限制和假设。
Toby Speight

5

似乎官方开发人员网站提到了Objc中一种计算文本行数的解决方案。但是,它假定您对配置了布局管理器,文本存储和文本容器的文本视图有引用。不幸的是,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
    }
}

1
这是最好的答案。其他答案不能正确考虑文字换行,这可能导致许多行太短,因为它们有效地使用了字符换行。
罗伯·施密德

请注意,请确保使用NSAttributedString。如果尝试仅从文本创建NSTextStorage,则将获得随机结果。
罗伯·施密德

当提供带有RTL中文本的标签时,这种方法不能很好地工作。它使文本左对齐。
Yarneo,

总是返回第1行的号码,
Dhiru '20

4

对@王子的回答之后,我现在实现一个品类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

5
Apple文档的leading内容为“lineHeight改为使用该属性”。事实上,在我的UILabel,字体的leading属性等于0
杰拉德

4

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

NSInteger numberOfLines = [self lineCountForText:@"YOUR TEXT"];

- (int)lineCountForText:(NSString *) text
{
    UIFont *font = [UIFont systemFontOfSize: 15.0];
    int width=Your_LabelWidht;

    CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin  attributes:@{NSFontAttributeName : font} context:nil];
    return ceil(rect.size.height / font.lineHeight);
}

4

迅捷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,它以较早的swift版本提供了解决方案,并提到了layoutIfNeeded()的重要性。


var actualNumberOfLines:Int {layoutIfNeeded()让myText = text!作为NSString,让rect = CGSize(width:bounds.width,height:CGFloat.greatestFiniteMagnitude)let labelSize = myText.boundingRect(with:rect,options:.usesLineFragmentOrigin,attribute:[NSAttributedString.Key.font:font as Any],上下文:nil)return Int(ceil(CGFloat(labelSize.height)/ font.lineHeight))}
Bunthoeun

完美的作品!
Senocico Stelian

1

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

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

0

Xamarin.iOS

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

这将获得可见线的数量。

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代替font.pointSize
  • round()除后的行数

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

这将是“标签”和“行数”的确切动态高度。编码愉快!


0

Nor️也不行单靠单行也是不够的。lineHeightleading

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

因此,例如,具有5条线的标签的高度由5lineHeight和4组成leading(但是,前导值通常足够小,以至于上述解决方案可以起作用,直到开始使用多条线为止。

因此正确的(伪)公式应为:

(frame.size.height + font.leading) / (font.lineHeight + font.leading)

另外,如果属性字符串的附件太大(比ascender字体的附件大),则它还会更改该行的行高。


-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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.