iOS Label最后一行中間截斷顯示縮略符

一、前言

繼上次本文本有行間距,當時交互有另一個需求堰乔,需要在文本最后一行省略符號放中間,只省略到最后一行的中間累舷。如下圖需求浩考。Label的自帶LineBreakMode不支持如下的設(shè)置。便要自己處理被盈,經(jīng)過網(wǎng)上的資料參考和同事J學(xué)習(xí)探討析孽,這里記錄一下解決方案與過程。

圖1.png

二只怎、分析

文本只需要最后一行進行處理袜瞬,因此取得能取得文本最后一行,并進行計算身堡,當最后一行的文本超過中間邓尤,則截取字符到中間,并增加一個“...”字符串。

三汞扎、解決方案

核心方法為網(wǎng)上大神所寫獲得Label每行文本字符串數(shù)組的方法季稳,對拿到的最后一行進行處理。處理方式還是要利用獲取每行文本的方法澈魄,傳入一個顯示label寬度的一半label景鼠。這時計算出來的最后一行的點點點省略號,誤差就在一個字符痹扇。

//獲得Label每行的文本字符串數(shù)組
- (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每行文本數(shù)組
    NSArray *separatedLines = [NSString getSeparatedLinesFromLabel:self.label];
    
    NSMutableString *limitedText = [NSMutableString string];
    if ( separatedLines.count >= self.label.numberOfLines )  {//當超過最大行數(shù)
        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調(diào)用一下 setLineBreakByTruncatingLastLineMiddle 方法浓恶,同時需要設(shè)置一下最大行數(shù)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

五结笨、思考

系統(tǒng)可以直接Label的lineBreakMode包晰,如果可以給系統(tǒng)lineBreakMode增加一個枚舉類型NSLineBreakByTruncatingLastLineMiddle,那在使用的時候禀梳,直接設(shè)置一下就好了是該多方便杜窄。不知道這個想法的可行性,需要學(xué)習(xí)了解看看算途。如果后續(xù)有這樣的解決方案塞耕,再來補充。

經(jīng)過探討嘴瓤,想給系統(tǒng)lineBreakMode增加一個枚舉還是行不通的扫外,畢竟系統(tǒng)的代碼沒有開源,其次廓脆,要是能修改也是自己能用筛谚。所以,遇到這種情況停忿,可以寫一個類方法驾讲,或者是給類增加一個屬性,例如otherLineBreakMode席赂,進行處理吮铭。

六、參考資料

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颅停,一起剝皮案震驚了整個濱河市谓晌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌癞揉,老刑警劉巖纸肉,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溺欧,死亡現(xiàn)場離奇詭異,居然都是意外死亡柏肪,警方通過查閱死者的電腦和手機姐刁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烦味,“玉大人龙填,你說我怎么就攤上這事」詹妫” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵扇商,是天一觀的道長凤瘦。 經(jīng)常有香客問我,道長案铺,這世上最難降的妖魔是什么蔬芥? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮控汉,結(jié)果婚禮上笔诵,老公的妹妹穿的比我還像新娘。我一直安慰自己姑子,他們只是感情好乎婿,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著街佑,像睡著了一般谢翎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沐旨,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天森逮,我揣著相機與錄音,去河邊找鬼磁携。 笑死褒侧,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的谊迄。 我是一名探鬼主播闷供,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鳞上!你這毒婦竟也來了这吻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤篙议,失蹤者是張志新(化名)和其女友劉穎唾糯,沒想到半個月后怠硼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡移怯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年香璃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舟误。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡葡秒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嵌溢,到底是詐尸還是另有隱情眯牧,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布赖草,位于F島的核電站学少,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秧骑。R本人自食惡果不足惜版确,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乎折。 院中可真熱鬧绒疗,春花似錦、人聲如沸骂澄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酗洒。三九已至士修,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間樱衷,已是汗流浹背棋嘲。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矩桂,地道東北人沸移。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像侄榴,于是被迫代替她去往敵國和親雹锣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容