含有Emoji表情的文本計算高度

brighttang 8年前發布 | 26K 次閱讀 iOS開發 移動開發

最進開發社區時遇到一個需求,產品那邊的需求是要做成和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

 

 本文由用戶 brighttang 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!