我更新了啥?
我只是最近学会了的排版,于是选了我比较受关注的一篇重新排了一下版(确实美观了很多),顺便再记录了一下我处理云旺表情时遇到无法正则时的处理办法,仅此而已
NSString转NSAttributedString
最近研究了含表情的字符串,我们实现像的其实不难,输入法都支持,但是如果想换成自己需要的图片表情,甚至GIF动画表情,就要花一番功夫了。除了利用webview写HTML的方法外,有一种更加清明的方法,那就是属性字符串,即NSAttributedString、NSMutableAttributedString,顾名思义后者就是可变的而已。
首先,先实现普通字符串转属性字符串吧(copy的):
+ (NSMutableAttributedString *)stringToAttributeString:(NSString *)text{
//先把普通的字符串text转化生成Attributed类型的字符串
NSMutableAttributedString * attStr = [[NSMutableAttributedString alloc]initWithString:text];
//正则表达式 ,例如 [(呵呵)] =
NSString * zhengze = @"\\[\\([a-zA-Z0-9\u4e00-\u9fa5]+\\)\\]";
NSError * error;
NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:zhengze options:NSRegularExpressionCaseInsensitive error:&error];
if (!re)
{
//打印错误
NSLog(@"error=%@",[error localizedDescription]);
}
NSArray * arr = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)];//遍历字符串,获得所有的匹配字符串
NSBundle *bundle = [NSBundle mainBundle];
NSString * path = [bundle pathForResource:@"emj" ofType:@"plist"]; //plist文件,制作一个 数组,包含文字,表情图片名称
NSArray * face = [[NSArray alloc]initWithContentsOfFile:path];//获取 所有的数组
//如果有多个表情图,必须从后往前替换,因为替换后Range就不准确了
for (int j =(int) arr.count - 1; j >= 0; j--) {
//NSTextCheckingResult里面包含range
NSTextCheckingResult * result = arr[j];
for (int i = 0; i < face.count; i++) {
if ([[text substringWithRange:result.range] isEqualToString:face[i][@"key"]])//从数组中的字典中取元素
{
NSString * imageName = [NSString stringWithString:face[i][@"picture"]];
//添加附件,图片
NSTextAttachment * textAttachment = [[NSTextAttachment alloc]init];
//调节表情大小
textAttachment.bounds=CGRectMake(0, 0, 20, 20);
textAttachment.image = [UIImage imageNamed:imageName];
NSAttributedString * imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
//替换未图片附件
[attStr replaceCharactersInRange:result.range withAttributedString:imageStr];
break;
}
}
}
return attStr;
}
NSAttributedString转NSString
=====================================
当然,你肯定会需要转回来:
//把带有图片的属性字符串转成普通的字符串
+ (NSString *)textString:(NSAttributedString *)attributedText
{
NSMutableAttributedString * resutlAtt = [[NSMutableAttributedString alloc]initWithAttributedString:attributedText];
EmoticonsHelper * helper = [EmoticonsHelper new];
//枚举出所有的附件字符串
[attributedText enumerateAttributesInRange:NSMakeRange(0, attributedText.length) options:NSAttributedStringEnumerationReverse usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
//从字典中取得那一个图片
NSTextAttachment * textAtt = attrs[@"NSAttachment"];
if (textAtt)
{
UIImage * image = textAtt.image;
NSString * text = [helper stringFromImage:image];
[resutlAtt replaceCharactersInRange:range withString:text];
}
}];
return resutlAtt.string;
}
其中EmoticonsHelper实现了图片和字符串的一一对应,和需求相关就不贴代码了.
含表情字符串的尺寸计算
会不会需要属性字符串的尺寸大小呢?不用着急,直接有代码:
+(CGSize)getAttributedTextSize:(NSString *)text
{
//先把普通的字符串text转化生成Attributed类型的字符串
NSMutableAttributedString * attStr = [[NSMutableAttributedString alloc]initWithString:text];
NSString * zhengze = @"\\[\\([a-zA-Z0-9\u4e00-\u9fa5]+\\)\\]";
NSError * error;
NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:zhengze options:NSRegularExpressionCaseInsensitive error:&error];
if (!re)
{
NSLog(@"正则表达式匹配错误%@" ,[error localizedDescription]);
}
NSArray * arr = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)];
if (!arr.count)//说明字符串中没有表情通配符,是普通的文本,则计算文本size
{
NSDictionary *dic=@{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGSize size1=[text boundingRectWithSize:CGSizeMake(160, 1000) options:NSStringDrawingUsesLineFragmentOrigin attributes:dic context:nil].size;
if (size1.height<=60)
{
size1.height=60;
}else
{
size1.height+=15;
}
return size1;
}
NSBundle *bundle = [NSBundle mainBundle];
NSString * path = [bundle pathForResource:@"emj" ofType:@"plist"];
NSArray * face = [[NSArray alloc]initWithContentsOfFile:path];
//如果有多个表情图,必须从后往前替换,因为替换后Range就不准确了
for (int j =(int) arr.count - 1; j >= 0; j--) {
//NSTextCheckingResult里面包含range
NSTextCheckingResult * result = arr[j];
for (int i = 0; i < face.count; i++) {
if ([[text substringWithRange:result.range] isEqualToString:face[i][@"key"]])
{
NSString * imageName = [NSString stringWithString:face[i][@"picture"]];
NSTextAttachment * textAttachment = [[NSTextAttachment alloc]init];
textAttachment.image = [UIImage imageNamed:imageName];
NSAttributedString * imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attStr replaceCharactersInRange:result.range withAttributedString:imageStr];
break;
}
}
}
CGSize size2 = [attStr boundingRectWithSize:CGSizeMake(180, 1000) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
size2.height+=40; //表情文字增加高度
return size2;//返回属性字符串的尺寸
}
输入时显示表情
当然,以上这些都是网上随便可以找的到的,下面要写一点不一样的东西了
首先我们知道和字符串相关的UI控件呢不外乎那么几种,怎么样利用上属性字符串呢?
UITextView、UITextField
以UITextView为例,要表情图片神奇的显示在输入中,你需要如此做:
- (void)emoticonAttributedStringTextView:(UITextView *)textView andAttributedString:(NSAttributedString *)attributedString{
[textView.textStorage insertAttributedString:attributedString atIndex:textView.selectedRange.location];
textView.selectedRange = NSMakeRange(textView.selectedRange.location+1, 0);
//重置格式
NSRange wholeRange = NSMakeRange(0,textView.textStorage.length);
[textView.textStorage removeAttribute:NSFontAttributeName range:wholeRange];
[textView.textStorage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20.0f] range:wholeRange];
}
这样不但能显示表情图片到你的TextView里,还能通过UIFont
设置显示的大小。
UILabel
这个控件就不用多说了,直接有个属性名字叫attributedText,直接赋值就能显示了。
附上 demo
另外,附上做云旺表情支持的时候的代码,仅供参考
- (NSMutableAttributedString *)stringToAttributeString:(NSString *)text{
//先把普通的字符串text转化生成Attributed类型的字符串
NSDictionary *attribs = @{NSFontAttributeName: messageFont};
if(![XFTools textNotEmpty:text]){
text = @"";
}
NSMutableAttributedString * attStr = [[NSMutableAttributedString alloc]initWithString:text attributes:attribs];
NSArray *arrEmo =[[YWEmoticonFactory sharedInstance]shareEmoticonsInfoWithType:YWEmoticonTypeStaticImage];
NSArray *arrEmo2 =[[YWEmoticonFactory sharedInstance]shareEmoticonsSymbolsWithType:YWEmoticonTypeStaticImage];
NSMutableDictionary *dic =[[YWEmoticonFactory sharedInstance]shareEmoticonImagesWithType:YWEmoticonTypeStaticImage];
for (int j = 0; j < arrEmo2.count; ) {
NSString *subStr = arrEmo2[j];
NSRange subRange = [attStr.string rangeOfString:subStr];
if (subRange.location!=NSNotFound) {
for (int i = 0; i < arrEmo.count; i++) {
YWEmoticon *emo = arrEmo[i];
if ([subStr isEqualToString:emo.emoticon])
{
NSString * imageName = emo.fileName;
NSTextAttachment * textAttachment = [[NSTextAttachment alloc]init];
textAttachment.bounds=CGRectMake(0, 2, 17, 17);
textAttachment.image =[dic objectForKey:imageName];
NSAttributedString * imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attStr replaceCharactersInRange:subRange withAttributedString:imageStr];
break;
}
}
}else{
j++;
}
}
return attStr;
}
本文就到此结束了。。。。。