50行代码实现图文混排案例一

开头

本文是技术集中的第一篇技术性文章,所以就记录一点简单且浅显易懂的东西。

现在即时通讯和朋友圈这两块功能基本上属于app的标配功能了吧。图文混排在这两块中使用最为常见,我已经做好了demo:图文混排demo

文中会讲述几点小技巧:图文混排动态计算文字长度图片拉伸方法

以前的做法

在以前做图文混排的时候,经常使用OHAttributedLabel,后来苹果吸取了一些第三方的优点,对NSString做了扩展,作者也不再更新,推荐用系统的方法来实现图文混排。具体请自行百度或者google关键字OHAttributedLabel

现在的做法

苹果在iOS7中推出了一个新的类NSTextAttachment它是做图文混排的利器,本文就是用这个类,只用50行代码实现文字与表情混排,当然也可以实现段落中的图文混排,与CoreText比起来实在是简单了太多,下面讲述两个案例。

案例一

先上效果图,聊天界面中的图文混排:

要实现这样的效果,code4app上似乎有很多种做法,还有一些奇葩的一个字符一个label,但是今天要讲述的做法,是目前为止我看到的最简单的做法了,只用一个UILabel,需要用到UILabel的attributedText属性。

首先,需要组装一个表情和文字对应的plist文件,plist中的键值对如下:

图-2

本文用一个工具类来实现一个转换的方法,你也可以给NSString添加一个类别来实现。

第一步,解析plist文件,转化为数组。

NSString*filePath = [[NSBundlemainBundle]pathForResource:@"emoticons" ofType:@"plist"]; NSArray*face = [NSArray arrayWithContentsOfFile:filePath];

第二步,将字符串转换为可变属性字符串,并通过正则表达式匹配出所有的要替换的字符。

//1、创建一个可变的属性字符串 NSMutableAttributedString*attributeString = [[NSMutableAttributedString alloc]initWithString:text]; //2、通过正则表达式来匹配字符串 NSString*regex_emoji =@"\\[[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\]";//匹配表情 NSError*error =nil; NSRegularExpression*re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error]; if(!re) { NSLog(@"%@", [errorlocalizedDescription]); returnattributeString; } NSArray*resultArray = [rematchesInString:text options:0 range:NSMakeRange(0, text.length)];

数组中都是NSTextCheckingResult对象,它包含了特殊字符在整个字符串中的位置等信息。

第三步,将特殊字符与对应表情关联

NSMutableArray*imageArray = [NSMutableArray arrayWithCapacity:resultArray.count]; //根据匹配范围来用图片进行相应的替换 for(NSTextCheckingResult *match in resultArray) { //获取数组元素中得到range NSRangerange = [match range]; //获取原字符串中对应的值 NSString*subStr = [text substringWithRange:range]; for(inti =0; i < face.count; i ++) { if([face[i][@"cht"] isEqualToString:subStr]) { //face[i][@"png"]就是我们要加载的图片 //新建文字附件来存放我们的图片,iOS7才新加的对象 NSTextAttachment*textAttachment = [[NSTextAttachment alloc] init]; //给附件添加图片 textAttachment.image= [UIImage imageNamed:face[i][@"png"]]; //调整一下图片的位置,如果你的图片偏上或者偏下,调整一下bounds的y值即可 textAttachment.bounds=CGRectMake(0, -8, textAttachment.image.size.width, textAttachment.image.size.height); //把附件转换成可变字符串,用于替换掉源字符串中的表情文字 NSAttributedString*imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment]; //把图片和图片对应的位置存入字典中 NSMutableDictionary*imageDic = [NSMutableDictionary dictionaryWithCapacity:2]; [imageDic setObject:imageStr forKey:@"image"]; [imageDic setObject:[NSValuevalueWithRange:range] forKey:@"range"]; //把字典存入数组中 [imageArray addObject:imageDic]; } } }

第四步,将特殊字符替换成图片

//4、从后往前替换,否则会引起位置问题 for(int i = (int)imageArray.count-1; i >=0; i--) { NSRange range; [imageArray[i][@"range"] getValue:&range]; //进行替换 [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]]; }

用法:

NSString*content =@"文字加上表情[得意][酷][呲牙]"; NSMutableAttributedString *attrStr = [Utility emotionStrWithString:content]; _contentLabel.attributedText= attrStr;

案例二:

需要实现的效果:

有了上面的方法,这个效果更容易实现,只需要将某些图片给它设置一个固定的字符对应即可。

与以上方法主要不同点在于正则表达式:

//2、匹配字符串 NSError *error  = nil; NSRegularExpression*re = [NSRegularExpression regularExpressionWithPattern:string options:NSRegularExpressionCaseInsensitive error:&error]; if(!re) { NSLog(@"%@", [error localizedDescription]); return attributeString; }

用法:

NSString*praiseStr =@"路人甲、路人乙"; NSString*praiseInfo = [NSStringstringWithFormat:@"<点赞> %@",praiseStr]; NSDictionary*attributesForAll =@{NSFontAttributeName:[UIFontsystemFontOfSize:14.0],NSForegroundColorAttributeName:[UIColorgrayColor]}; NSMutableAttributedString*attrStr = [Utility exchangeString:@"<点赞>" withText:praiseInfoimageName:@"dynamic_love_blue"];

彩蛋

1、计算动态文字的长度

NSMutableAttributedString*content = [Utility emotionStrWithString:_dynamic.text]; [content addAttribute:NSFontAttributeName value:kContentFont  range:NSMakeRange(0, content.length)]; CGSizemaxSize =CGSizeMake(kDynamicWidth,MAXFLOAT); CGSizeattrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;

其中NSMutableAttributedString类型的字符串可以添加多种属性,并且在计算的时候必须设置字符大小等属性。

2、图片拉伸

在iOS5之前可以用stretchableImageWithLeftCapWidth: topCapHeight:

iOS5之中用resizableImageWithCapInsets:

iOS6开始多了一个参数resizableImageWithCapInsets:resizingMode:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏怀英的自我修炼

Java漫谈2

本周我们的Java漫谈从一个段子说起。话说有一个老程序退休了,在家闲着没事便开始学习写毛笔字,焚香,研墨,铺纸。站在薄如蝉翼白似雪的宣纸面前,提笔闭目。只见那人...

34180
来自专栏java工会

深度思考编程的艺术

17980
来自专栏微信公众号:Java团长

超详细:常用的设计模式汇总

简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它...

7810
来自专栏互联网开发者交流社区

元素化设计原理及规则v1.0

15750
来自专栏非著名程序员

七夕节,程序员特有的表白方式!

以上这首告白书,来自于网络,我只是找到了这首程序员的告白诗,最早的时间出现在 2009 年 1 月 5 日,不知道作者是谁。(侵删)

31110
来自专栏web前端教室

[先行者课程] -- 用js实现倒计时功能的业务逻辑

今天是2017年3月19号,周日,我们一起来学习“倒计时”这个前端“需求”。 一,看一下上周的作业,视差滚动的作业; 二,开始分享学习倒计时应用。 因为时间的关...

30650
来自专栏mathor

HDOJ1257最少拦截系统

 这个题一开始我百思不得其解,后来看了一眼别人的题解标题,最长上升子序列?我当时还纳闷,这和最长上升子序列有什么关系,后来仔细一想还确实是。因为导弹拦截系统...

10020
来自专栏陈纪庚

使用装饰者模式做有趣的事情

装饰者模式是一种为函数或类增添特性的技术,它可以让我们在不修改原来对象的基础上,为其增添新的能力和行为。它本质上也是一个函数(在javascipt中,类也只是函...

8420
来自专栏Albert陈凯

2018-11-08 杀死If Else switch case(策略模式+工厂模式+map)套餐 Kill 项目中的switch case

为了便于理解,举个没有业务逻辑的例子,基于这个例子上进行优化。 现在是12:47,举个饭后吃水果的例子哈哈哈(逃 假设我们可以选择的水果有香蕉、西瓜和苹果。吃香...

20930
来自专栏PHP在线

编程语言中的闭包

首先,我觉得,一个概念,如果不理解也不影响使用的话,那么,就没必要去理解它、去学习它。闭包就是这样一个概念,你不理解它也能很好的用它。俺这两年写as3程序,是天...

38240

扫码关注云+社区

领取腾讯云代金券