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

含有Emoji表情的文本计算高度_第1张图片
屏幕快照 2016-11-13 下午9.55.05.png

最进开发社区时遇到一个需求,产品那边的需求是要做成和QQ空间一样的评论功能,在评论内容中要显示昵称,并且点击昵称要进入个人主页。查了好多资料,看了YYText和TTTAttributedLabel的官方文章,也没找到结果,最后自己抱着试一试的态度,结果还真的实现了需求,记录下来,分享给大家,希望对你们会有所帮助
先来一张效果图

含有Emoji表情的文本计算高度_第2张图片
7E8F2CA3-1F82-4993-9423-AE46D6FFF4EA.png

这个是最后的效果图,点击浅蓝色文字会跳到个人主页,不过还有点小问题,文字的间距还需要微调下。不过思路已经有了。
先说下自己遇到的问题。点击文字链接用的是YYText,实现起来很简单,但是问题是,当字符串中含有Emoji表情时,行间距就出现的了问题。本来我们需要的是这样的。

含有Emoji表情的文本计算高度_第3张图片
屏幕快照 2016-11-13 下午9.22.58.png

但是使用YYText或者TTTAttributedLabel后变成了这样

含有Emoji表情的文本计算高度_第4张图片
屏幕快照 2016-11-13 下午9.26.41.png

间距明显不一样

首先说明下,对于含有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; //返回最后处理完成的字符串
}

此时你看到的效果是这样的

含有Emoji表情的文本计算高度_第5张图片
屏幕快照 2016-11-13 下午9.41.33.png

这样就实现了需求了。

你可能感兴趣的:(含有Emoji表情的文本计算高度)