How to check if UILabel is truncated?

62,449

Solution 1

You can calculate the width of the string and see if the width is greater than label.bounds.size.width

NSString UIKit Additions has several methods for computing the size of the string with a specific font. However, if you have a minimumFontSize for your label that allows the system to shrink the text down to that size. You may want to use sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode: in that case.

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

Solution 2

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

swift4: (attributes param of boundingRect 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
    }

}

Solution 3

EDIT: I just saw my answer was upvoted, but the code snippet I gave is deprecated.
Now the best way to do this is (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");
}

Note the calculated size is not integer value. So if you do things like int height = rect.size.height, you will lose some floating point precision and may have wrong results.

Old answer (deprecated) :

If your label is multiline, 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");
}

Solution 4

Swift 3

You can count the number of lines after assigning the string and compare to the max 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 {
        guard numberOfLines > 0 else { return false }
        return countLabelLines() > numberOfLines
    }
}

Solution 5

you can make 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;
}
Share:
62,449
Randall
Author by

Randall

Updated on October 10, 2021

Comments

  • Randall
    Randall over 2 years

    I have a UILabel that can be varying lengths depending on whether or not my app is running in portrait or landscape mode on an iPhone or iPad. When the text is too long to show on one line and it truncates I want the user to be able to press it and get a popup of the full text.

    How can I check to see if the UILabel is truncating the text? Is it even possible? Right now I'm just checking for different lengths based on what mode I'm in but it does not work super well.

  • Randall
    Randall almost 14 years
    Thanks, this is exactly what I needed. The only difference was, sizeWithFont: returns a CGSize.
  • progrmr
    progrmr almost 14 years
    Ah, thanks for pointing that out, I've corrected the sample code.
  • Martin
    Martin over 11 years
    from the doc : textRectForBounds:limitedToNumberOfLines: "You should not call this method directly"...
  • DongXu
    DongXu over 11 years
    @Martin thank you,I see that,the implement here is limited.but when you call this method after setting bounds and text, it will work well
  • Amelia777
    Amelia777 almost 10 years
    sizeWithFont is deprecated use: [label.text sizeWithAttributes:@{NSFontAttributeName : label.font}];
  • Can Leloğlu
    Can Leloğlu about 9 years
    You are dividing width by height and if it is bigger than number of line (which might very well be 0) you are saying label is truncated. There is no way this works.
  • Raz
    Raz about 9 years
    @CanLeloğlu please test it. It is a working example.
  • Can Leloğlu
    Can Leloğlu about 9 years
    What if the numberOfLines is equal to zero?
  • Anton Matosov
    Anton Matosov almost 9 years
    Thanks! Usage of intrinsicContentSize instead of frame was the solution to my problem when UILabel height is actually enough to fit the text, but it has limited number of lines and thus is still truncating.
  • Ash
    Ash over 8 years
    Why do you +1 when setting the limitedToNumberOfLines?
  • ambientlight
    ambientlight about 8 years
    replace height of 999999.0 with CGFloat(FLT_MAX)
  • Paul
    Paul about 8 years
    @fatuhoku numberOfLines returns the maximum number of lines used to display the text as outlined in the UILabel class reference: developer.apple.com/library/ios/documentation/UIKit/Referenc‌​e/…
  • zero3nna
    zero3nna over 7 years
    for swift 3 i would use CGFloat.greatestFiniteMagnitude
  • Can Poyrazoğlu
    Can Poyrazoğlu about 7 years
    For some reason, this is returning NO even when the text doesn't fit into the label
  • vrwim
    vrwim about 7 years
    @Ash to check if the label is higher when it is allowed more room for the text.
  • Mohammadalijf
    Mohammadalijf almost 7 years
    nice answer but its better to use calculated property instead of func : var isTruncated: Bool { if let string = self.text { let size: CGSize = (string as NSString).boundingRect( with: CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil).size return (size.height > self.bounds.size.height) } return false }
  • Fadi Abuzant
    Fadi Abuzant almost 6 years
    if label has number of line try multiply width with number of line like this if (size.width > label.bounds.size.width*label.numberOfLines) { ... }
  • Jovan Jovanovski
    Jovan Jovanovski over 5 years
    Thanks for this code, it worked for me apart from some border cases when using auto layout. I fixed them by adding: setNeedsLayout() layoutIfNeeded() at the beginning of the method.
  • Bibek
    Bibek over 5 years
    every time it gives NSNotFound only
  • pulse4life
    pulse4life over 5 years
    This didn't work for me because I was using an NSAttributedString. To get it to work, I needed to modify the attributes value to use: attributedText?.attributes(at: 0, effectiveRange: nil)
  • Crt Gregoric
    Crt Gregoric over 5 years
    Great answer, had to change it a bit for my requirements, but worked perfectly. I was also using an attributed string - so for attributes I used: (attributedText?.attributes(at: 0, effectiveRange: nil) ?? [.font: font]), just make sure to check whether the labelText is not empty when using this solution.
  • JimmyLee
    JimmyLee over 5 years
    This is the nice answer for swift. Thanks.
  • amodkanthe
    amodkanthe over 4 years
    this working fine for me thanks !!are there any updates or modification for this?
  • Elijah
    Elijah over 4 years
    Great answer. The only issue is attributedText is never nil, even when you don't set it. So, I implemented this as two vars isTextTruncated and isAttributedTextTruncated.
  • Lucas Chwe
    Lucas Chwe over 4 years
    @Harris it says default is nil in the uilabel.h file
  • Elijah
    Elijah over 4 years
    @LucasChwe I know, but it's not true in practice. You can try it for yourself and see. fyi, forums.developer.apple.com/thread/118581
  • Glenn Posadas
    Glenn Posadas almost 4 years
    Axel's answer didn't work for this. This one did. Thanks!
  • Admin
    Admin over 3 years
    you may need to call layoutIfNeeded either on the label or within the code of isTruncated depending on when you are checking this
  • Adrian
    Adrian over 2 years
    does intrinsicContentSize.width work for both text and attributedText?