如何找到 UILabel 的行数

Posted

技术标签:

【中文标题】如何找到 UILabel 的行数【英文标题】:How to find UILabel's number of Lines 【发布时间】:2010-11-13 12:58:22 【问题描述】:

我使用 wrap 方法在 UILabel 中显示了文本。 现在我想知道UILabel中有多少行。

如果有任何方法可以找到 UILabel 的行数。

谢谢。

【问题讨论】:

***.com/questions/4082041/… 【参考方案1】:

正如所指出的,这篇文章涉及如何获取高度,而不是行数。要获取行数,

    获取单个字母的高度,例如@"A"。 将字符串的高度除以上面1中得到的高度。

例如

CGFloat unitHeight = [@"A" heightForWidth:width usingFont:font];
CGFloat blockHeight = [text heightForWidth:width usingFont:font];
NSInteger numberOfLines =        ceilf(blockHeight / unitHeight); 
// need to #include <math.h> for ^^^^^

从 iOS 7 开始,获取标签所需高度的方式发生了变化。要获取高度,可以使用以下代码:

NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize labelSize = (CGSize)width, FLT_MAX;
CGRect r = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@NSFontAttributeName: font context:context];

高度为r.size.height。请注意,必须提供font。为方便起见,您可以将其放入 NSString 的类别中,例如

@implementation NSString (HeightCalc)

- (CGFloat)heightForWidth:(CGFloat)width usingFont:(UIFont *)font

    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
    CGSize labelSize = (CGSize)width, FLT_MAX;
    CGRect r = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@NSFontAttributeName: font context:context];
    return r.size.height;


@end

(顺便说一句,如果不使用 ARC,请进行内存管理。)

适用于 iOS 6 及更低版本:

假设您有一个UILabel *myLabel,并且您想找出标签的高度(通过一些调整,您可以通过将高度除以一些适当的数字来获得行数,具体取决于字体大小)。

UILabel *myLabel;
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font 
                            constrainedToSize:myLabel.frame.size 
                                lineBreakMode:UILineBreakModeWordWrap];
CGFloat labelHeight = labelSize.height;

希望对您有所帮助。如果它不起作用,请告诉我,我会进一步挖掘。此外,未经测试的代码,但从参考工作。

对于更完整的示例,这是我放入视图控制器的 viewDidLoad: 方法中的代码:

[super viewDidLoad];
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50,50,200,350)];
myLabel.numberOfLines = 0;
myLabel.lineBreakMode = UILineBreakModeWordWrap;
myLabel.text = @"This is some text in a UILabel which is long enough to wrap around the lines in said UILabel. This is a test, this is only a test.";
[self.view addSubview:myLabel];
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font 
                            constrainedToSize:myLabel.frame.size 
                                lineBreakMode:UILineBreakModeWordWrap];
CGFloat labelHeight = labelSize.height;
NSLog(@"labelHeight = %f", labelHeight);
[myLabel release];

NSLog 的输出如下:

2010-11-15 18:25:27.817 so_labelheight[728:307] labelHeight = 126.000000

【讨论】:

它显示以下两个错误 //error: incompatible type for argument 2 of 'sizeWithFont:constrainedToSize:lineBreakMode:' error: request for member 'size' in something not a structure or union 当然 .size 不是 UILabel 上的属性,但它可能应该类似于 myLabel.frame.size 或 myLabel.bounds.size (不确定你想要哪个)。 啊,是的,错过了那个。感谢 Wim H。将上面的示例修复为使用 frame.size。 只是一个建议:与其使用(CGSize)width, 999,不如使用(CGSize)width, FLT_MAX,这样就很清楚这个数字的来源了。 这是回答问题的好方法,但实际上并不能回答所述问题。问题是关于行数。考虑到这一点,您能否更新您的答案?【参考方案2】:

对于ios7及以上,officially sanctioned way统计行数是使用TextKit:

func numberOfLinesForString(string: String, size: CGSize, font: UIFont) -> Int 
    let textStorage = NSTextStorage(string: string, attributes: [NSFontAttributeName: font])

    let textContainer = NSTextContainer(size: size)
    textContainer.lineBreakMode = .ByWordWrapping
    textContainer.maximumNumberOfLines = 0
    textContainer.lineFragmentPadding = 0

    let layoutManager = NSLayoutManager()
    layoutManager.textStorage = textStorage
    layoutManager.addTextContainer(textContainer)

    var numberOfLines = 0
    var index = 0
    var lineRange : NSRange = NSMakeRange(0, 0)
    for (; index < layoutManager.numberOfGlyphs; numberOfLines++) 
        layoutManager.lineFragmentRectForGlyphAtIndex(index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
    

    return numberOfLines

【讨论】:

这通常很好用,但是当 textContainer 有 lineBreakMode = .byWordWrapping 时,行尾可以有无限数量的空格(然后在容器之外),但是没有行break 并且它不会计算额外的行。有什么可以防止的吗?【参考方案3】:

-sizeWithFont:constrainedToSize:lineBreakMode 方法现已弃用。您现在需要使用-boundingRectWithSize:options:attributes:context: 方法。

这里有一个例子:

CGSize boundingRectSize = CGSizeMake(widthToConstrainTo, CGFLOAT_MAX);
NSDictionary *attributes = @NSFontAttributeName : [UIFont fontWithName:fontName size:14];
CGRect labelSize = [labelString boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                attributes:attributes
                                                   context:nil];

在上面的例子中,我知道我想限制标签的宽度,但由于我不确定高度,我只是使用CGFLOAT_MAX 将高度参数最大化。对于options,如果您要计算可以是任意行数的标签的大小,则需要使用NSStringDrawingUsesLineFragmentOriginNSStringDrawingUsesFontLeading

【讨论】:

【参考方案4】:

如果你在 Swift 2+/iOS 8 中寻找这个答案,它看起来像这样:

func numberOfLinesInLabel(yourString: String, labelWidth: CGFloat, labelHeight: CGFloat, font: UIFont) -> Int 

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.minimumLineHeight = labelHeight
    paragraphStyle.maximumLineHeight = labelHeight
    paragraphStyle.lineBreakMode = .ByWordWrapping

    let attributes: [String: AnyObject] = [NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle]

    let constrain = CGSizeMake(labelWidth, CGFloat(Float.infinity))

    let size = yourString.sizeWithAttributes(attributes)
    let stringWidth = size.width

    let numberOfLines = ceil(Double(stringWidth/constrain.width))

    return Int(numberOfLines)

【讨论】:

谢谢@AvielGross。编辑以反映您的意见。 这里“约束”的目的是什么?【参考方案5】:

sizeWithFont 在 iOS 7 中已弃用,您可以改用它:

- (int)lineCountForText:(NSString *) text

    UIFont *font = ...

    CGRect rect = [text boundingRectWithSize:CGSizeMake(200, MAXFLOAT)
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@NSFontAttributeName : font
                                     context:nil];

    return ceil(rect.size.height / font.lineHeight);

【讨论】:

【参考方案6】:

(我最初发布了我的答案here,但没有足够的声誉来评论或标记重复项。)

我发现的其他答案不尊重 UILabelnumberOfLines 属性,当它设置为 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 子类化为具有自定义边缘插入(例如通过覆盖drawTextInRect:,这是我发现here 的一个巧妙技巧),那么您必须记住在计算@ 时考虑这些插入987654330@以上。例如:CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)

【讨论】:

【参考方案7】:
func getHeight(text:  NSString, width:CGFloat, font: UIFont) -> CGFloat

    let rect = text.boundingRect(with: CGSize.init(width: width, height: CGFloat.greatestFiniteMagnitude), options: ([NSStringDrawingOptions.usesLineFragmentOrigin,NSStringDrawingOptions.usesFontLeading]), attributes: [NSFontAttributeName:font], context: nil)
    return rect.size.height

文本:您需要使用给定字符串查找其高度的标签

width:UILabel的宽度

字体:UILabel 的字体

【讨论】:

【参考方案8】:

Swift 5.5 基于上述良好的回答和反馈,包括自动布局。

extension UILabel 
    @objc var numberOfVisibleLines: Int 
        if !translatesAutoresizingMaskIntoConstraints 
            layoutIfNeeded()
        

        let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
        let textHeight = sizeThatFits(maxSize).height
        let lineHeight = font.lineHeight
        let numberOfVisibleLines = lineHeight == 0 ? numberOfLines : Int(ceil(textHeight / lineHeight)) - 1
        return numberOfVisibleLines >= 0 ? numberOfVisibleLines : numberOfLines
    

【讨论】:

以上是关于如何找到 UILabel 的行数的主要内容,如果未能解决你的问题,请参考以下文章

自定义大小的表格视图单元格中的 UILabel 中的行数

计算动态UILabel的行数(iOS7)

动画改变 UILabel 的行数

没有为 UILabel 获得正确的行数

当 UITableViewCell 中的行数固定时,UILabel 占用空间?

根据包含的文本设置 UILabel 的行数 - Objective C 和/或 Swift