源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

iOS App开发中扩展RCLabel组件进行基于HTML的文本布局

  • 时间:2022-10-28 23:24 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:iOS App开发中扩展RCLabel组件进行基于HTML的文本布局
iOS系统是一个十分注重用户体验的系统,在iOS系统中,用户交互的方案也十分多,然而要在label中的某部分字体中添加交互行为确实不容易的,如果使用其他类似Button的控件来模拟,文字的排版又将是一个解决十分困难的问题。这个问题的由来是项目中的一个界面中有一些广告位标签,而这些广告位的标签却是嵌在文本中的,当用户点击文字标签的位置时,会跳转到响应的广告页。 CoreText框架和一些第三方库可以解决这个问题,但直接使用CoreText十分复杂,第三方库多注重于富文本的排版,对类似文字超链接的支持亦不是特别简洁,我们可以借助一些第三方的东西进行针对性更强,更易用的封装。 RCLabel是一个第三方的将html字符串进行文本布局的工具,代码十分轻巧,并且其是基于CoreText框架的,其原生性和扩展性十分强。 [b]一、扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计 [/b]在iOS开发中,图文混排一直都是UI编程的一个核心点,也有许多优秀的第三方引擎,其中很有名的一套图文混排的框架叫做DTCoreText。但是在前些日的做的一个项目中,我并没有采用这套框架,原因有二,一是这套框架体积非常大,而项目的需求其实并不太高;二是要在这套框架中修改一些东西,难度也非常大,我最终采用的是一个叫做RCLabel的第三方控件,经过一些简单的优化和完善,达到了项目的要求。 先来介绍一下我项目中的图文混排的需求:首先我从服务器中取到的数据是字符串,但是其中穿插图片的位置是一个HTML的图片标签,标签里的资源路径就是图片的请求地址。需要达到的要求是这些数据显示出来后,图片的位置要空出来,然后通过异步的网络请求获取图片的数据,再将图片插入文字中。 要自己实现一套这样的引擎确实会比较麻烦,幸运的是RCLabel可以完美的帮我们解析带有HTML标签的数据,进行图文混排,[code]我们先来看一下这个东西怎么用,下面是我封装的一个展示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];     } } [/code]RCLabel的用法很简单,总结来说只有三步: 1.初始化并设置frame 2.通过带html标签的数据进行属性的初始化 3.将属性进行set设置并重设视图frame RCLabel是很强大,并且代码很简练,但是其中处理图片的部分必须是本地的图片,即图片html标签中的路径必须是本地图片的名字,其内部是通过[UIImage ImageNamed:]这个方法进行图片的渲染的,所以要达到我们的需要,我们需要对其进行一些简单的扩展: 1、在属性设置方法中添加一个参数,来区分本地图片与网络图片: [code]//我在这个方法中添加了location这个bool值,实际上rclabel这个参数也是我添加的,是为了后面代理使用的 + (RTLabelComponentsStructure*)extractTextStyle:(NSString*)dataimage IsLocation:(BOOL)location withRCLabel:(RCLabel *)rcLabel; [/code]2、在实现方法中添加如下代码,因为原文件有1900多行,在其中弄清楚逻辑关系也确实费了我不小的力气,我这里只将我添加的代码贴过来 [code]#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];                                         });                                                                 }                                                                    }                                                             };                                                     });                     }                                                     }[/code] [b]二、视图类与模型类的设计 [/b]RCLabel的核心之处在于将HTML文本转换为富文本布局视图,因此我们可以将要显示的文本编程html字符串,将其可以进行用户交互的部分进行html超链接关联,RCLabel就检测到我们点击的区域进行响应逻辑的回调。设计类如下: .h文件 [code]//文本与超链接地址关联的model类 后面会说 @class YHBaseLinkingLabelModel; @protocol YHBaseLinkingLabelProtocol <NSObject> @optional /**  *点击超链接后出发的代理方法 model中有链接地址和文字  */ -(void)YHBaseLinkingLabelClickLinking:(YHBaseLinkingLabelModel *)model; /**  *尺寸改变后出发的方法  */ -(void)YHBaseLinkingLabelSizeChange:(CGSize)size; @end @interface YHBaseLinkingLabel : YHBaseView /**  *文字数组 里面存放这文字对应的超链接对象  */ @property(nonatomic,strong)NSArray<YHBaseLinkingLabelModel *> * textArray; @property(nonatomic,weak)id<YHBaseLinkingLabelProtocol>delegate; /**  *设置文字颜色  */ @property(nonatomic,strong)UIColor * textColor; /**  *设置超链接文字颜色  */ @property(nonatomic,strong)UIColor * linkColor; /**  *设置字体大小  */ @property(nonatomic,assign)NSUInteger fontSize; /**  *设置超链接字体大小  */ @property(nonatomic,assign)int linkingFontSize; /**  *设置是否显示下划线  */ @property(nonatomic,assign)BOOL isShowUnderLine; @end .m文件 @interface YHBaseLinkingLabel()<YHBaseHtmlViewProcotop> @end @implementation YHBaseLinkingLabel {     //以前博客中 封装的显示HTML字符串富文本的视图     YHBaseHtmlView * _label; } /* // 重载一些初始化方法 - (instancetype)init {     self = [super init];     if (self) {         _label = [[YHBaseHtmlView alloc]init];         [self addSubview:_label];         [_label mas_makeConstraints:^(MASConstraintMaker *make) {             make.leading.equalTo(@0);             make.trailing.equalTo(@0);             make.top.equalTo(@0);             make.bottom.equalTo(@0);         }];          _label.delegate=self;     }     return self; } - (instancetype)initWithCoder:(NSCoder *)coder {     self = [super initWithCoder:coder];     if (self) {         _label = [[YHBaseHtmlView alloc]init];         [self addSubview:_label];         [_label mas_makeConstraints:^(MASConstraintMaker *make) {             make.leading.equalTo(@0);             make.trailing.equalTo(@0);             make.top.equalTo(@0);             make.bottom.equalTo(@0);         }];          _label.delegate=self;     }     return self; } - (instancetype)initWithFrame:(CGRect)frame {     self = [super initWithFrame:frame];     if (self) {         _label = [[YHBaseHtmlView alloc]init];         [self addSubview:_label];         [_label mas_makeConstraints:^(MASConstraintMaker *make) {             make.leading.equalTo(@0);             make.trailing.equalTo(@0);             make.top.equalTo(@0);             make.bottom.equalTo(@0);         }];         _label.delegate=self;     }     return self; } //设置文本数组 -(void)setTextArray:(NSArray<YHBaseLinkingLabelModel *> *)textArray{     _textArray = textArray;     //进行html转换     NSString * htmlString = [self transLinkingDataToHtmlStr:textArray];     //进行布局     [_label reSetHtmlStr:htmlString];     } -(void)setTextColor:(UIColor *)textColor{     _textColor = textColor;     _label.fontColor = textColor; } -(void)setLinkColor:(UIColor *)linkColor{     _linkColor = linkColor;     _label.linkingColor = linkColor; } -(void)setFontSize:(NSUInteger)fontSize{     _fontSize = fontSize;     [_label setFontSize:(int)fontSize]; } -(void)setLinkingFontSize:(int)linkingFontSize{     _linkingFontSize = linkingFontSize;     [_label setLinkingSize:linkingFontSize]; } -(void)setIsShowUnderLine:(BOOL)isShowUnderLine{     _isShowUnderLine = isShowUnderLine;     [_label setShowUnderLine:isShowUnderLine]; } -(NSString *)transLinkingDataToHtmlStr:(NSArray<YHBaseLinkingLabelModel *> *)data{     NSMutableString * mutStr = [[NSMutableString alloc]init];     for (int i=0; i<data.count; i++) {     //这个model中存放的是超链接部分的文字和对应的url         YHBaseLinkingLabelModel * model = data[i];         if (!model.linking) {             [mutStr appendString:model.text];         }else {             [mutStr appendString:@"<a href="];             [mutStr appendString:model.linking];             [mutStr appendString:@">"];             [mutStr appendString:model.text];             [mutStr appendString:@"</a>"];         }     }     return mutStr; } #pragma mark delegate //点击的回调 -(void)YHBaseHtmlView:(YHBaseHtmlView *)htmlView ClickLink:(NSString *)url{     for (YHBaseLinkingLabelModel * model in _textArray) {         if ([model.linking isEqualToString:url]) {             if ([self.delegate respondsToSelector:@selector(YHBaseLinkingLabelClickLinking:)]) {                 [self.delegate YHBaseLinkingLabelClickLinking:model];                 return;             }         }     } } //布局尺寸改变的回调 -(void)YHBaseHtmlView:(YHBaseHtmlView *)htmlView SizeChanged:(CGSize)size{     if ([self.delegate respondsToSelector:@selector(YHBaseLinkingLabelSizeChange:)]) {         [self.delegate YHBaseLinkingLabelSizeChange:size];     } } @end [/code]上面我们有用到一个YHBaseLinkingLabelModel类,这个类进行了链接与字符的映射,设计如下: [code]@interface YHBaseLinkingLabelModel : YHBaseModel /**  *文字内容  */ @property(nonatomic,strong)NSString * text; /**  *超链接地址 nil则为无  */ @property(nonatomic,strong)NSString * linking; @end [/code]YHBaseHtmlView类是对RCLabel的一层封装,其中也对RCLabel进行了一些优化和改动,代码较多且在上篇博客中有介绍,这里不再多做解释了。 在ViewController中写如下代码进行使用: [code]- (void)viewDidLoad {     [super viewDidLoad];     // Do any additional setup after loading the view, typically from a nib.    YHBaseLinkingLabel * label = [[YHBaseLinkingLabel alloc]initWithFrame:CGRectMake(100, 100, 200, 100)];     NSMutableArray * array = [[NSMutableArray alloc]init];     for (int i=0; i<6; i++) {         YHBaseLinkingLabelModel * model = [[YHBaseLinkingLabelModel alloc]init];         if (!(i%2)) {             model.text =[NSString stringWithFormat:@"第%d个标签",i];             model.linking = [NSString stringWithFormat:@"第%d个标签",i];         }else{             model.text = @",不能点得文字,";         }         [array addObject:model];     }     label.textColor = [UIColor blackColor];     label.linkColor = [UIColor purpleColor];     label.fontSize = 15;     label.linkingFontSize = 17;     label.isShowUnderLine=YES;     label.delegate=self;     label.textArray = array;     [self.view addSubview:label];    } -(void)YHBaseLinkingLabelClickLinking:(YHBaseLinkingLabelModel *)model{     NSLog(@"%@",model.linking); } [/code]运行效果如下: [img]http://files.jb51.net/file_images/article/201607/201671291423648.jpg?201661291436[/img] 效果不错,并且十分简单易用,对吧。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部