How to check if UILabel is truncated?

I have UILabel , which can vary depending on whether my application works in portrait or landscape mode on an iPhone or iPad. When the text is too long to be displayed on one line and it truncates, I want the user to be able to click it and get a popup with full text.

How can I check if UILabel text UILabel text? Is it possible? Right now I'm just checking a different length based on what mode I am in, but it doesn’t work very well.

+95
ios objective-c iphone uilabel truncate
Jun 19 '10 at 20:25
source share
14 answers

You can calculate the line width and see if label.bounds.size.width

NSString UIKit Add-ons has several methods for calculating the size of a string with a specific font. However, if you have a minimal check box for your shortcut that allows the system to compress text to this size. In this case, you can use sizeWithFont: minFontSize: actualFontSize: forWidth: lineBreakMode:.

 CGSize size = [label.text sizeWithAttributes:@{label.font}]; if (size.width > label.bounds.size.width) { ... } 
+102
Jun 19 '10 at 20:34
source share

Swift (as an extension) - works for multi-line uilabel:

swift4: ( attributes boundingRect parameter changed slightly)

 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 } } 
+78
Jul 16 '15 at 16:29
source share

EDIT: I only saw that my answer was approved, but the code snippet I gave is out of date.
Now the best way to do this (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"); } 

Please note that the calculated size is not an integer. Therefore, if you do things like int height = rect.size.height , you will lose some floating point precision and may have incorrect results.

Old answer (deprecated):

If your label is multi-line, you can use this code:

 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"); } 
+19
Nov 07 '12 at 15:38
source share

you can create a category with 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; } 
+13
Oct 26
source share

Use this category to determine if a tag has been truncated on iOS 7 or later.

 // 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 
+9
Jul 01 '14 at 10:37
source share

To add an answer to iDev , you must use intrinsicContentSize instead of frame to make it work for 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; } 
+8
Oct 22 '14 at 2:34
source share

Swift 3

You can count the number of lines after assigning a line and compare with the maximum number of lines of the label.

 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 } } 
+7
Mar 24 '17 at 14:27
source share

This works for 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"); } 
+2
Dec 17 '14 at a.m.
source share

I wrote a category for working with UILabel truncation. Works on iOS 7 and later. Hope it helps! tail trimming 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 
+2
Jun 13 '15 at 0:31
source share

To add to @iDev , I changed self.frame.size.height to use label.frame.size.height , and also did not use NSStringDrawingUsesLineFontLeading . After these changes, I reached a perfect calculation when truncation will occur (at least for my case).

 - (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; } 
+1
Oct 09 '14 at 17:51
source share

Since all of the above answers use depreciated methods, I thought this could be useful:

 - (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; } 
0
Apr 23 '14 at 9:03
source share

To handle iOS 6 (yes, some of us still need), here is another extension for @iDev's answer. The key conclusion is that for iOS 6, make sure your UILabel numberOfLines is set to 0 before calling sizeThatFits; if not, this will give you a result that says that to draw label text you need to draw the number needed to draw numberOfLines, the height value.

 - (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); } 
0
Mar 30 '15 at 19:20
source share

Swift 3 Solution

I think the best solution is to (1) create a UILabel with the same properties as the label you are checking for truncation, call (2) .sizeToFit() , (3) compare the attributes of the dummy label with your actual label.

For example, if you want to check whether one aligned label with a different width is trimmed or not, you can use this extension:

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

... but again, you can easily change the above code to suit your needs. So let your label be multi-line and have different heights. Then the extension will look something like this:

 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 } } } 
-one
Jan 26 '17 at 10:31 on
source share

It would not be possible to set the title attribute for the label, and the full label would be displayed on it.

you can calculate the length of the label and the width of the div (convert to length - jQuery / Javascript - How to convert a pixel value (20 pixels) to a numeric value (20) ).

set jquery to set the title if the length is greater than the width of the div.

 var divlen = parseInt(jQuery("#yourdivid").width,10); var lablen =jQuery("#yourlabelid").text().length; if(lablen < divlen){ jQuery("#yourlabelid").attr("title",jQuery("#yourlabelid").text()); } 
-6
Feb 04 '16 at 2:33
source share



All Articles