How to check if UILabel is truncated?

前端 未结 20 2566
不知归路
不知归路 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:29

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

    Because all the answers above 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 讨论(0)
  • 2020-11-28 03:35

    To add to iDev 's answer, you should use intrinsicContentSize instead of frame, to make it works 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;
    }
    
    0 讨论(0)
  • 2020-11-28 03:35
    extension UILabel {
    
    public func resizeIfNeeded() -> CGFloat? {
        guard let text = text, !text.isEmpty else { return nil }
    
        if isTruncated() {
            numberOfLines = 0
            sizeToFit()
            return frame.height
        }
        return nil
    }
    
    func isTruncated() -> Bool {
        guard let text = text, !text.isEmpty else { return false }
    
        let size: CGSize = text.size(withAttributes: [NSAttributedStringKey.font: font])
        return size.width > self.bounds.size.width
        }
    }
    

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

    0 讨论(0)
  • 2020-11-28 03:36

    To handle iOS 6 (yes, some of us still have to), here's yet another expansion to @iDev's answer. The key takeaway is that, for iOS 6, to make sure your UILabel's numberOfLines is set to 0 before calling sizeThatFits; if not, it'll give you a result that says "the points to draw numberOfLines worth of height" is needed to draw the label text.

    - (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 (i.e. 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 讨论(0)
  • 2020-11-28 03:37

    I have written a category for working with UILabel's truncation. Works on iOS 7 and later. Hope it helps ! uilabel tail truncation

    @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
    
    0 讨论(0)
提交回复
热议问题