含有Emoji表情的文本計算高度
最進開發社區時遇到一個需求,產品那邊的需求是要做成和QQ空間一樣的評論功能,在評論內容中要顯示昵稱,并且點擊昵稱要進入個人主頁。查了好多資料,看了YYText和TTTAttributedLabel的官方文章,也沒找到結果,最后自己抱著試一試的態度,結果還真的實現了需求,記錄下來,分享給大家,希望對你們會有所幫助
先來一張效果圖
這個是最后的效果圖,點擊淺藍色文字會跳到個人主頁,不過還有點小問題,文字的間距還需要微調下。不過思路已經有了。
先說下自己遇到的問題。點擊文字鏈接用的是YYText,實現起來很簡單,但是問題是,當字符串中含有Emoji表情時,行間距就出現的了問題。本來我們需要的是這樣的。
但是使用YYText或者TTTAttributedLabel后變成了這樣
間距明顯不一樣
首先說明下,對于含有Emoji表情的字符串,使用UILabel來展示沒有任何問題,間距也都是一樣的,但是使用YYText或者TTTAttributedLabel來添加文字的點擊事件之后都會變成含有Emoji表情的行高比正常文字的行高要高。
本以為YYText或者TTTAttributedLabel本身有方法可以設置,很遺憾,我沒找到(如果你知道的話,請留言告訴我),無奈之下只能使用比較笨的方法。
先說下我的思路:目前的結果是含有Emoji表情的行高要比預期的高,于是就想到,能不能獲取每行的內容,然后循環遍歷每行的文字,判斷是否含友Emoji表情,如果有則不做處理,如果沒有這設置行高和含有Emoji表情的行高一樣的高度,問題不就解決了嗎。
第一步:先要獲取,每行的文字
/**
* 獲取每行的文字
*
* @param text 文本內容
* @param font 字體
* @param maxWidth 容器的最大寬度
*
* @return 存儲每行文字的數組
*/
- (NSArray *)getSeparatedLinesFromtext:(NSString *)text font:(UIFont *)font maxWidth:(CGFloat)maxWidth
{
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,maxWidth,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;
}
使用此方法,可以獲取每行的文字的內容。
第二步:判斷是否含有Emoji表情
//判斷是否含有Emoji表情
+ (BOOL)stringContainsEmoji:(NSString *)string
{
__block BOOL returnValue =NO;
[string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
const unichar hs = [substring characterAtIndex:0];
// surrogate pair
if (0xd800) {
if (0xd800 <= hs && hs <= 0xdbff) {
if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
if (0x1d000 <= uc && uc <= 0x1f77f) {
returnValue =YES;
}
}
}else if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
if (ls == 0x20e3) {
returnValue =YES;
}
}else {
// non surrogate
if (0x2100 <= hs && hs <= 0x27ff) {
returnValue =YES;
}else if (0x2B05 <= hs && hs <= 0x2b07) {
returnValue =YES;
}else if (0x2934 <= hs && hs <= 0x2935) {
returnValue =YES;
}else if (0x3297 <= hs && hs <= 0x3299) {
returnValue =YES;
}else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
returnValue =YES;
}
}
}
}];
return returnValue;
}
第三步:循環存儲每行文字內容的數組,處理字符串
- (NSMutableAttributedString *)changeLineSpacing:(NSArray *)stringList {
NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc] init];
for (NSString *string in stringList) {
//如果含有Emoji表情,不做處理
if ([NSString stringContainsEmoji:string]) {
NSMutableAttributedString *contentEmojistring = [[NSMutableAttributedString alloc] initWithString:string];
[mutableString appendAttributedString:contentEmojistring];
}else { //否則設置段落樣式,行高為4(這個高度要根據自己的需求慢慢的試)
NSMutableAttributedString *unContentEmojistring = [[NSMutableAttributedString alloc] initWithString:string];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 4;
[unContentEmojistring addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [unContentEmojistring length])];
[mutableString appendAttributedString:unContentEmojistring];
}
}
return mutableString; //返回最后處理完成的字符串
}
此時你看到的效果是這樣的
這樣就實現了需求了。
來自:http://www.jianshu.com/p/96df4e0ffac7