美文网首页UILabel相关iOS DeveloperiOS
iOS Label最后一行中间截断显示缩略符

iOS Label最后一行中间截断显示缩略符

作者: Cass__ | 来源:发表于2016-10-30 09:30 被阅读1780次

    一、前言

    继上次本文本有行间距,当时交互有另一个需求,需要在文本最后一行省略符号放中间,只省略到最后一行的中间。如下图需求。Label的自带LineBreakMode不支持如下的设置。便要自己处理,经过网上的资料参考和同事J学习探讨,这里记录一下解决方案与过程。

    图1.png

    二、分析

    文本只需要最后一行进行处理,因此取得能取得文本最后一行,并进行计算,当最后一行的文本超过中间,则截取字符到中间,并增加一个“...”字符串。

    三、解决方案

    核心方法为网上大神所写获得Label每行文本字符串数组的方法,对拿到的最后一行进行处理。处理方式还是要利用获取每行文本的方法,传入一个显示label宽度的一半label。这时计算出来的最后一行的点点点省略号,误差就在一个字符。

    //获得Label每行的文本字符串数组
    - (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label {
        NSString *text = [label text];
        UIFont *font = [label font];
        CGRect rect = [label bounds];
    
        CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL);
        NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
        [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
        CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
        CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
        NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
        NSMutableArray *linesArray = [[NSMutableArray alloc]init];
        for (id line in lines) {
            CTLineRef lineRef = (__bridge CTLineRef )line;
            CFRange lineRange = CTLineGetStringRange(lineRef);
            NSRange range = NSMakeRange(lineRange.location, lineRange.length);
            NSString *lineString = [text substringWithRange:range];
            [linesArray addObject:lineString];
        }
        return (NSArray *)linesArray;
    }
    

    再利用此方法处理最后一行文本:

       //Label每行文本数组
        NSArray *separatedLines = [NSString getSeparatedLinesFromLabel:self.label];
        
        NSMutableString *limitedText = [NSMutableString string];
        if ( separatedLines.count >= self.label.numberOfLines )  {//当超过最大行数
            for (int i = 0 ; i < self.label.numberOfLines; i++)  {
                if ( i == self.label.numberOfLines - 1) {//处理最后一行文本
                    UILabel *lastLineLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.label.frame.size.width/2, MAXFLOAT)];
                    lastLineLabel.text = separatedLines[self.label.numberOfLines - 1];
                    NSArray *subSeparatedLines = [NSString getSeparatedLinesFromLabel:lastLineLabel];
                    NSString *lastLineText = [subSeparatedLines firstObject];
                    NSInteger lastLineTextCount = lastLineText.length;
                    [limitedText appendString:[NSString stringWithFormat:@"%@...",[lastLineText substringToIndex:lastLineTextCount]]];
                } else {//非最后一行,则将文本进行存储
                    [limitedText appendString:separatedLines[i]];
                }
            }  
        } else {
            [limitedText appendString:self.text];
        }
        
        self.label.text = limitedText;
    

    四、封装与使用

    写一个Label分类,对需要进行最后一行中间省略号的Label调用一下 setLineBreakByTruncatingLastLineMiddle 方法,同时需要设置一下最大行数numberOfLines。

    #import "UILabel+QT.h"
    #import <CoreText/CoreText.h>
    
    @implementation UILabel (QT)
    
    - (void)setLineBreakByTruncatingLastLineMiddle {
    
        if ( self.numberOfLines <= 0 ) {
            return;
        }
        NSArray *separatedLines = [self getSeparatedLinesArray];
    
        NSMutableString *limitedText = [NSMutableString string];
        if ( separatedLines.count >= self.numberOfLines ) {
    
            for (int i = 0 ; i < self.numberOfLines; i++) {
                if ( i == self.numberOfLines - 1) {
                    UILabel *lastLineLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width/2, MAXFLOAT)];
                    lastLineLabel.font = self.font;
                    lastLineLabel.text = separatedLines[self.numberOfLines - 1];
    
                    NSArray *subSeparatedLines = [lastLineLabel getSeparatedLinesArray];
                    NSString *lastLineText = [subSeparatedLines firstObject];
                    NSInteger lastLineTextCount = lastLineText.length;
                    [limitedText appendString:[NSString stringWithFormat:@"%@...",[lastLineText substringToIndex:lastLineTextCount]]];
                } else {
                    [limitedText appendString:separatedLines[i]];
                }
            }
    
    
        } else {
            [limitedText appendString:self.text];
        }
    
        self.text = limitedText;
    
    }
    
    - (NSArray *)getSeparatedLinesArray {
        NSString *text = [self text];
        UIFont   *font = [self font];
        CGRect    rect = [self frame];
    
        CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL);
        NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
        [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
    
        CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
    
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
    
        CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
    
        NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);
        NSMutableArray *linesArray = [[NSMutableArray alloc]init];
    
        for (id line in lines) {
            CTLineRef lineRef = (__bridge CTLineRef )line;
            CFRange lineRange = CTLineGetStringRange(lineRef);
            NSRange range = NSMakeRange(lineRange.location, lineRange.length);
    
            NSString *lineString = [text substringWithRange:range];
            [linesArray addObject:lineString];
        }
        return (NSArray *)linesArray;
    }
    
    @end
    

    五、思考

    系统可以直接Label的lineBreakMode,如果可以给系统lineBreakMode增加一个枚举类型NSLineBreakByTruncatingLastLineMiddle,那在使用的时候,直接设置一下就好了是该多方便。不知道这个想法的可行性,需要学习了解看看。如果后续有这样的解决方案,再来补充。

    经过探讨,想给系统lineBreakMode增加一个枚举还是行不通的,毕竟系统的代码没有开源,其次,要是能修改也是自己能用。所以,遇到这种情况,可以写一个类方法,或者是给类增加一个属性,例如otherLineBreakMode,进行处理。

    六、参考资料

    http://stackoverflow.com/questions/34867231/issue-get-lines-array-of-string-inn-label

    个人博客地址:https://casscqt.github.io

    相关文章

      网友评论

        本文标题:iOS Label最后一行中间截断显示缩略符

        本文链接:https://www.haomeiwen.com/subject/jxaeuttx.html