在iOS开发中,图文混排一直都是UI编程的一个核心点,也有许多优秀的第三方引擎,其中颇有名的一套图文混排的框架叫作DTCoreText。可是在前些日的作的一个项目中,我并无采用这套框架,缘由有二,一是这套框架体积很是大,而项目的需求其实并不过高;二是要在这套框架中修改一些东西,难度也很是大,我最终采用的是一个叫作RCLabel的第三方控件,通过一些简单的优化和完善,达到了项目的要求。html
先来介绍一下我项目中的图文混排的需求:首先我从服务器中取到的数据是字符串,可是其中穿插图片的位置是一个HTML的图片标签,标签里的资源路径就是图片的请求地址。须要达到的要求是这些数据显示出来后,图片的位置要空出来,而后经过异步的网络请求获取图片的数据,再将图片插入文字中。编程
要本身实现一套这样的引擎确实会比较麻烦,幸运的是RCLabel能够完美的帮咱们解析带有HTML标签的数据,进行图文混排,咱们先来看一下这个东西怎么用,下面是我封装的一个展现html数据的view:缓存
@interface YHBaseHtmlView()<YHRTLabelImageDelegate> { //RCLabel对象 RCLabel * _rcLabel; //保存属性 用于异步加载完成后刷新 RTLabelComponentsStructure * _origenComponent; //含html标签的数据字符串 NSString * _srt; } @end @implementation YHBaseHtmlView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { //将rclabel初始化 _rcLabel = [[RCLabel alloc]init]; [self addSubview:_rcLabel]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _rcLabel = [[RCLabel alloc]initWithFrame:frame]; [self addSubview:_rcLabel]; } return self; } -(void)reSetHtmlStr:(NSString *)htmlStr{ _srt = htmlStr; //这个代理是我额外添加的 后面解释 _rcLabel.imageDelegate=self; //设置frame _rcLabel.frame=CGRectMake(0, 0, self.frame.size.width, 0); //设置属性 _origenComponent = [RCLabel extractTextStyle:htmlStr IsLocation:NO withRCLabel:_rcLabel]; _rcLabel.componentsAndPlainText = _origenComponent; //获取排版后的size CGSize size = [_rcLabel optimumSize]; //从新设置frame _rcLabel.frame=CGRectMake(0, 0, _rcLabel.frame.size.width, size.height); self.frame=CGRectMake(self.frame.origin.x, self.frame.origin.y, _rcLabel.frame.size.width, size.height); } //这是我额外添加的代理方法的实现 -(void)YHRTLabelImageSuccess:(RCLabel *)label{ _origenComponent = [RCLabel extractTextStyle:_srt IsLocation:NO withRCLabel:_rcLabel]; _rcLabel.componentsAndPlainText = _origenComponent; CGSize size = [_rcLabel optimumSize]; _rcLabel.frame=CGRectMake(0, 0, _rcLabel.frame.size.width, size.height); self.frame=_rcLabel.frame; if ([self.delegate respondsToSelector:@selector(YHBaseHtmlView:SizeChanged:)]) { [self.delegate YHBaseHtmlView:self SizeChanged:self.frame.size]; } }
RCLabel的用法很简单,总结来讲只有三步:服务器
1.初始化并设置frame网络
2.经过带html标签的数据进行属性的初始化框架
3.将属性进行set设置并重设视图frame异步
RCLabel是很强大,而且代码很简练,可是其中处理图片的部分必须是本地的图片,即图片html标签中的路径必须是本地图片的名字,其内部是经过[UIImage ImageNamed:]这个方法进行图片的渲染的,因此要达到咱们的须要,咱们须要对其进行一些简单的扩展:async
一、在属性设置方法中添加一个参数,来区分本地图片与网络图片:ide
//我在这个方法中添加了location这个bool值,实际上rclabel这个参数也是我添加的,是为了后面代理使用的 + (RTLabelComponentsStructure*)extractTextStyle:(NSString*)dataimage IsLocation:(BOOL)location withRCLabel:(RCLabel *)rcLabel;
二、在实现方法中添加以下代码,由于原文件有1900多行,在其中弄清楚逻辑关系也确实费了我不小的力气,我这里只将我添加的代码贴过来优化
#warning 这里进行了兼容性处理 if (location) { //本地图片的渲染 if (tempURL) { UIImage *tempImg = [UIImage imageNamed:tempURL]; component.img = tempImg; } }else{//这里作远程图片数据的处理 //这里我进行了缓存的操做,这个缓存中心是我封装的框架中的另外一套东西,这里能够不用在乎 //先读缓存 NSData * ceche = [[YHBaseCecheCenter sharedTheSingletion] readCecheFile:tempURL fromPath:YHBaseCecheImage]; if (ceche) { UIImage * tempImg = [UIImage imageWithData:ceche]; component.img=tempImg; }else{ //在分线程中进行图片数据的获取 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ if (tempURL) { NSData * data = [YHBaseData getDataWithUrl:tempURL]; if (data) { //获取完成后村缓存 //作缓存 [[YHBaseCecheCenter sharedTheSingletion]writeCecheFile:data withFileID:tempURL toPath:YHBaseCecheImage]; //赋值 回调代理 UIImage * tempImg = [UIImage imageWithData:data]; component.img=tempImg; //这里代理是我添加的,当图片下载完成后 通知视图从新排版 if ([[rcLabel imageDelegate]respondsToSelector:@selector(YHRTLabelImageSuccess:)]) { //在主线程中执行回调 //这个地方要在主线程中执行,不然刷新会有延时 dispatch_async(dispatch_get_main_queue(), ^{ [[rcLabel imageDelegate] YHRTLabelImageSuccess:rcLabel]; }); } } }; }); } }
经过如上简单的扩展,基本达到了项目中的需求,这里把个人一些想法和思路分享给你们,有更好的解决方案,或者同是开发爱好者,欢迎指点与交流,个人QQ是316045346。
专一技术,热爱生活,交流技术,也作朋友。
——珲少 QQ群:203317592