一、前言
繼上次本文本有行間距,當時交互有另一個需求堰乔,需要在文本最后一行省略符號放中間,只省略到最后一行的中間累舷。如下圖需求浩考。Label的自帶LineBreakMode不支持如下的設(shè)置。便要自己處理被盈,經(jīng)過網(wǎng)上的資料參考和同事J學(xué)習(xí)探討析孽,這里記錄一下解決方案與過程。
二只怎、分析
文本只需要最后一行進行處理袜瞬,因此取得能取得文本最后一行,并進行計算身堡,當最后一行的文本超過中間邓尤,則截取字符到中間,并增加一個“...”字符串。
三汞扎、解決方案
核心方法為網(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