How to UILabel Linebreak set character wrap + truncate tail?

52 Views Asked by At

I want to set UILabel to character wrap + truncate tail. If I only set it to truncate tail, it breaks lines for word wrapping. How can I achieve this?"

NSLineBreakByCharWrapping | NSLineBreakByTruncatingTail

I try it but failed

2

There are 2 best solutions below

1
Sam Hoffmann On

I would consider looking into the numberOfLines property on UILabel. I am not sure the exact behavior without testing this, but if you set the numberOfLines = 2 and then the lineBreakMode = .byTruncatingTail you might be able to get this functionality by sacrificing a dynamic number of lines.

2
Seokmin Jeong On
+ (void)addEllipsisAtLabel:(nonnull UILabel *)label ellipsis:(nonnull NSString *)ellipsis {
    if (label == nil || label.text == nil || label.text.length == 0 || ellipsis == nil) return;
    if (label.numberOfLines <= 1) return;
    if (!(label.lineBreakMode == NSLineBreakByCharWrapping)) return;
    
//    int lines = [THISUTILCLASS numberOfLine:label content:label.text];
    CGSize maxSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
    NSInteger lines = [THISUTILCLASS numberOfLinesForString: label.text size:maxSize font:label.font];
    NSUInteger index = label.text.length;

    while (lines > label.numberOfLines) {
        NSString *subStr = [label.text substringToIndex: index];
        if (!subStr) {
            return;
        }
        
        NSString *combineStr = [NSString stringWithFormat:@"%@%@", subStr, ellipsis];
        
//        int newLines = [THISUTILCLASS numberOfLine:label content:combineStr];
        NSInteger newLines = [THISUTILCLASS numberOfLinesForString: combineStr size:maxSize font:label.font];
        
        if (newLines > label.numberOfLines) {
            if (--index <= 0) return;
        } else {
            label.text = combineStr;
            return;
        }
    }
}


+ (int)numberOfLine:(nonnull UILabel *)label content:(nonnull NSString *)content {
    if (label == nil || content == nil || content.length == 0) return 0;
    
    CGSize maxSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
    
    CGRect rect = [content boundingRectWithSize:maxSize
                                        options:NSStringDrawingUsesLineFragmentOrigin | label.lineBreakMode
                                     attributes:@{NSFontAttributeName:label.font}
                                        context:nil];
    
    return (int)(ceil((rect.size.height / label.font.lineHeight)));
}


+ (NSInteger)numberOfLinesForString:(nonnull NSString *)string size:(CGSize)size font:(nonnull UIFont *)font {
    if (string == nil || font == nil) return 0;
    
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:string attributes:@{NSFontAttributeName: font}];
    
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
    textContainer.lineBreakMode = NSLineBreakByWordWrapping;
    textContainer.maximumNumberOfLines = 0;
    textContainer.lineFragmentPadding = 0;
    
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    [layoutManager setTextStorage:textStorage];
    [layoutManager addTextContainer:textContainer];
    
    NSInteger numberOfLines = 0;
    NSUInteger index = 0;
    NSRange lineRange = NSMakeRange(0, 0);
    while (index < [layoutManager numberOfGlyphs]) {
        [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&lineRange];
        index = NSMaxRange(lineRange);
        numberOfLines++;
    }
    
    return numberOfLines;
}