最进开发社区时遇到一个需求,产品那边的需求是要做成和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; //返回最后处理完成的字符串
}
此时你看到的效果是这样的
这样就实现了需求了。