How to check if UILabel is truncated?

前端 未结 20 2573
不知归路
不知归路 2020-11-28 02:53

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

相关标签:
20条回答
  • 2020-11-28 03:11

    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");
    }
    
    0 讨论(0)
  • 2020-11-28 03:13

    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");
    }
    
    0 讨论(0)
  • 2020-11-28 03:13

    This is it. This works with attributedText, before falling back to plain text, which makes a lot of sense for us folks who deal with multiple font families, sizes, and even NSTextAttachments!

    Works fine with autolayout, but obviously the constraints must be defined and set before we check isTruncated, otherwise the label itself wont even know how to lay itself out, so no way it would even know if its truncated.

    It doesnt work to approach this problem with just a plain NSString and sizeThatFits. Im not sure how people were getting positive results like that. BTW, as mentioned numerous times, using sizeThatFits is not ideal at all because it takes into account numberOfLines for the resulting size, which defeats the whole purpose of what we are trying to do, because isTruncated would always return false regardless if its truncated or not.

    extension UILabel {
        var isTruncated: Bool {
            layoutIfNeeded()
    
            let rectBounds = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
            var fullTextHeight: CGFloat?
    
            if attributedText != nil {
                fullTextHeight = attributedText?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, context: nil).size.height
            } else {
                fullTextHeight = text?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil).size.height
            }
    
            return (fullTextHeight ?? 0) > bounds.size.height
        }
    }
    
    0 讨论(0)
  • 2020-11-28 03:13

    Wouldnt it be easy to set the title attribute for the label , setting this will display full label when hovered.

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

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

    var divlen = parseInt(jQuery("#yourdivid").width,10);
    var lablen =jQuery("#yourlabelid").text().length;
    if(lablen < divlen){
    jQuery("#yourlabelid").attr("title",jQuery("#yourlabelid").text());
    }
    
    0 讨论(0)
  • 2020-11-28 03:14

    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
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 03:15

    Swift 3 solution

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

    For example, if you want to check whether a one lined label that has varying width truncates or not, then 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 modify the above code to fit your needs. So let's say your label is multilined and has varying height. Then the extension would 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
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题