如何检查UILabel是否被截断?

我有一个UILabel ,可以是不同的长度取决于我的应用程序是否在iPhone或iPad上以纵向或横向模式运行。 当文本太长而不能显示在一行上,它会截断,我希望用户能够按下它,并获得全文的popup窗口。

如何检查UILabel是否截断了文本? 这甚至有可能吗? 现在我只是根据我在什么模式检查不同的长度,但它不能很好地工作。

您可以计算string的宽度,看看宽度是否大于label.bounds.size.width

NSString UIKit Additions有几种用特定字体计算string大小的方法。 但是,如果您的标签具有minimumFontSize,则允许系统将文本缩小到该大小。 你可能想要使用sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:在这种情况下。

 CGSize size = [label.text sizeWithAttributes:@{label.font}]; if (size.width > label.bounds.size.width) { ... } 

Swift(作为扩展) – 适用于多行uilabel:

swift4 🙁 boundingRect attributes参数稍有变化)

 extension UILabel { var isTruncated: Bool { guard let labelText = text else { return false } let labelTextSize = (labelText as NSString).boundingRect( with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).size return labelTextSize.height > bounds.size.height } } 

swift3:

 extension UILabel { var isTruncated: Bool { guard let labelText = text else { return false } let labelTextSize = (labelText as NSString).boundingRect( with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size return labelTextSize.height > bounds.size.height } } 

swift2:

 extension UILabel { func isTruncated() -> Bool { if let string = self.text { let size: CGSize = (string as NSString).boundingRectWithSize( CGSize(width: self.frame.size.width, height: CGFloat(FLT_MAX)), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil).size if (size.height > self.bounds.size.height) { return true } } return false } } 

编辑:我刚看到我的答案是upvoted,但我给的代码片段已弃用。
现在最好的办法是(ARC):

 NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; paragraph.lineBreakMode = mylabel.lineBreakMode; NSDictionary *attributes = @{NSFontAttributeName : mylabel.font, NSParagraphStyleAttributeName : paragraph}; CGSize constrainedSize = CGSizeMake(mylabel.bounds.size.width, NSIntegerMax); CGRect rect = [mylabel.text boundingRectWithSize:constrainedSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:attributes context:nil]; if (rect.size.height > mylabel.bounds.size.height) { NSLog(@"TOO MUCH"); } 

注意计算的大小不是整数值。 所以如果你做int height = rect.size.height这样的事情,你会失去一些浮点精度,并可能有错误的结果。

旧答案 (已弃用):

如果你的标签是多行的,你可以使用下面的代码:

 CGSize perfectSize = [mylabel.text sizeWithFont:mylabel.font constrainedToSize:CGSizeMake(mylabel.bounds.size.width, NSIntegerMax) lineBreakMode:mylabel.lineBreakMode]; if (perfectSize.height > mylabel.bounds.size.height) { NSLog(@"TOO MUCH"); } 

你可以用UILabel做一个类别

 - (BOOL)isTextTruncated { CGRect testBounds = self.bounds; testBounds.size.height = NSIntegerMax; CGRect limitActual = [self textRectForBounds:[self bounds] limitedToNumberOfLines:self.numberOfLines]; CGRect limitTest = [self textRectForBounds:testBounds limitedToNumberOfLines:self.numberOfLines + 1]; return limitTest.size.height>limitActual.size.height; } 

使用此类别查找iOS 7及更高版本上的标签是否被截断。

 // UILabel+Truncation.h @interface UILabel (Truncation) @property (nonatomic, readonly) BOOL isTruncated; @end // UILabel+Truncation.m @implementation UILabel (Truncation) - (BOOL)isTruncated { CGSize sizeOfText = [self.text boundingRectWithSize:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:@{ NSFontAttributeName : label.font } context: nil].size; if (self.frame.size.height < ceilf(sizeOfText.height)) { return YES; } return NO; } @end 

要添加到iDev的答案,你应该使用intrinsicContentSize而不是frame ,使其适用于Autolayout

 - (BOOL)isTruncated:(UILabel *)label{ CGSize sizeOfText = [label.text boundingRectWithSize: CGSizeMake(label.intrinsicContentSize.width, CGFLOAT_MAX) options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes: [NSDictionary dictionaryWithObject:label.font forKey:NSFontAttributeName] context: nil].size; if (self.intrinsicContentSize.height < ceilf(sizeOfText.height)) { return YES; } return NO; } 

Swift 3

您可以在分配string之后计算行数,并与标签的最大行数进行比较。

 import Foundation import UIKit extension UILabel { func countLabelLines() -> Int { // Call self.layoutIfNeeded() if your view is uses auto layout let myText = self.text! as NSString let attributes = [NSFontAttributeName : self.font] let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil) return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight)) } func isTruncated() -> Bool { if (self.countLabelLines() > self.numberOfLines) { return true } return false } } 

我已经写了一个类与UILabel的截断工作。 适用于iOS 7及更高版本。 希望能帮助到你 ! uilabel尾截断

 @implementation UILabel (Truncation) - (NSRange)truncatedRange { NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[self attributedText]]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [textStorage addLayoutManager:layoutManager]; NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self bounds].size]; textContainer.lineFragmentPadding = 0; [layoutManager addTextContainer:textContainer]; NSRange truncatedrange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:0]; return truncatedrange; } - (BOOL)isTruncated { return [self truncatedRange].location != NSNotFound; } - (NSString *)truncatedText { NSRange truncatedrange = [self truncatedRange]; if (truncatedrange.location != NSNotFound) { return [self.text substringWithRange:truncatedrange]; } return nil; } @end 

这适用于iOS 8:

 CGSize size = [label.text boundingRectWithSize:CGSizeMake(label.bounds.size.width, NSIntegerMax) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : label.font} context:nil].size; if (size.height > label.frame.size.height) { NSLog(@"truncated"); } 

要添加到@iDev所做的,我修改了self.frame.size.height以使用label.frame.size.height ,也没有使用NSStringDrawingUsesLineFontLeading 。 经过这些修改之后,我完成了截断何时发生的完美计算(至less在我的情况下)。

 - (BOOL)isTruncated:(UILabel *)label { CGSize sizeOfText = [label.text boundingRectWithSize: CGSizeMake(label.bounds.size.width, CGFLOAT_MAX) options: (NSStringDrawingUsesLineFragmentOrigin) attributes: [NSDictionary dictionaryWithObject:label.font forKey:NSFontAttributeName] context: nil].size; if (label.frame.size.height < ceilf(sizeOfText.height)) { return YES; } return NO; } 

因为上面所有的答案使用折旧方法,我认为这可能是有用的:

 - (BOOL)isLabelTruncated:(UILabel *)label { BOOL isTruncated = NO; CGRect labelSize = [label.text boundingRectWithSize:CGSizeFromString(label.text) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : label.font} context:nil]; if (labelSize.size.width / labelSize.size.height > label.numberOfLines) { isTruncated = YES; } return isTruncated; } 

为了处理iOS 6(是的,我们中的一些人仍然需要),这是对iDev的答案的另一个扩展。 关键是,对于iOS 6,在调用sizeThatFits之前确保你的UILabel的numberOfLines被设置为0; 如果不是的话,它会给你一个结果,说“绘制numberOfLines的高度的点”是需要绘制标签文本。

 - (BOOL)isTruncated { CGSize sizeOfText; // iOS 7 & 8 if([self.text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { sizeOfText = [self.text boundingRectWithSize:CGSizeMake(self.bounds.size.width,CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName:self.font} context:nil].size; } // iOS 6 else { // For iOS6, set numberOfLines to 0 (ie draw label text using as many lines as it takes) // so that siteThatFits works correctly. If we leave it = 1 (for example), it'll come // back telling us that we only need 1 line! NSInteger origNumLines = self.numberOfLines; self.numberOfLines = 0; sizeOfText = [self sizeThatFits:CGSizeMake(self.bounds.size.width,CGFLOAT_MAX)]; self.numberOfLines = origNumLines; } return ((self.bounds.size.height < sizeOfText.height) ? YES : NO); } 

Swift 3解决scheme

我认为最好的解决scheme是(1)创build一个UILabel ,其属性与您正在检查截断的标签相同, (2)调用.sizeToFit()(3)将虚拟标签的属性与您的实际标签进行比较。

例如,如果要检查宽度变化的单行标签是否截断,则可以使用以下扩展名:

 extension UILabel { func isTruncated() -> Bool { let label = UILabel(frame: CGRect(x: 0, y: 0, width: CGFloat.greatestFiniteMagnitude, height: self.bounds.height)) label.numberOfLines = 1 label.font = self.font label.text = self.text label.sizeToFit() if label.frame.width > self.frame.width { return true } else { return false } } } 

…但是,您可以轻松修改上面的代码以适应您的需求。 所以,假设您的标签是多线并且高度不一。 那么扩展名将如下所示:

 extension UILabel { func isTruncated() -> Bool { let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude)) label.numberOfLines = 0 label.font = self.font label.text = self.text label.sizeToFit() if label.frame.height > self.frame.height { return true } else { return false } } } 

如果设置标签的标题属性不容易,设置这将显示全部标签hover。

你可以计算标签的长度和div的宽度(转换为长度 – jQuery / JavaScript的 – 如何将像素值(20px)转换为数值(20) )。

设置jquery设置标题如果长度大于div宽度。

 var divlen = parseInt(jQuery("#yourdivid").width,10); var lablen =jQuery("#yourlabelid").text().length; if(lablen < divlen){ jQuery("#yourlabelid").attr("title",jQuery("#yourlabelid").text()); } 
Interesting Posts