扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计

简介:

扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计

        在iOS开发中,图文混排一直都是UI编程的一个核心点,也有许多优秀的第三方引擎,其中很有名的一套图文混排的框架叫做DTCoreText。但是在前些日的做的一个项目中,我并没有采用这套框架,原因有二,一是这套框架体积非常大,而项目的需求其实并不太高;二是要在这套框架中修改一些东西,难度也非常大,我最终采用的是一个叫做RCLabel的第三方控件,经过一些简单的优化和完善,达到了项目的要求。

        先来介绍一下我项目中的图文混排的需求:首先我从服务器中取到的数据是字符串,但是其中穿插图片的位置是一个HTML的图片标签,标签里的资源路径就是图片的请求地址。需要达到的要求是这些数据显示出来后,图片的位置要空出来,然后通过异步的网络请求获取图片的数据,再将图片插入文字中。

        要自己实现一套这样的引擎确实会比较麻烦,幸运的是RCLabel可以完美的帮我们解析带有HTML标签的数据,进行图文混排,我们先来看一下这个东西怎么用,下面是我封装的一个展示html数据的view:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
@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:]这个方法进行图片的渲染的,所以要达到我们的需要,我们需要对其进行一些简单的扩展:

1、在属性设置方法中添加一个参数,来区分本地图片与网络图片:

?
1
2
//我在这个方法中添加了location这个bool值,实际上rclabel这个参数也是我添加的,是为了后面代理使用的
+ (RTLabelComponentsStructure*)extractTextStyle:(NSString*)dataimage IsLocation:( BOOL )location withRCLabel:(RCLabel *)rcLabel;

2、在实现方法中添加如下代码,因为原文件有1900多行,在其中弄清楚逻辑关系也确实费了我不小的力气,我这里只将我添加的代码贴过来

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#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。


目录
相关文章
|
6月前
|
分布式计算 网络协议 Hadoop
Hadoop节点资源扩展网络配置
【4月更文挑战第16天】在扩展Hadoop节点资源时,网络配置至关重要。要点包括:保证网络连通性,确保新节点与集群间稳定通信;配置DNS和主机名解析,便于节点间通过名称通信;设置SSH免密码登录,简化集群管理;更新Hadoop配置文件以反映集群新状态;优化网络性能以提升数据传输效率;最后,测试验证确保集群正常运行和性能。具体配置应参照Hadoop版本及环境的官方文档。
52 4
|
6月前
|
传感器 算法 Go
基于EKF扩展卡尔曼滤波的传感器网络目标跟踪matlab仿真
基于EKF扩展卡尔曼滤波的传感器网络目标跟踪matlab仿真
|
8天前
|
缓存 负载均衡 网络协议
|
30天前
|
Java 应用服务中间件
面对海量网络请求,Tomcat线程池如何进行扩展?
【10月更文挑战第4天】本文详细探讨了Tomcat线程池相较于标准Java实用工具包(JUC)线程池的关键改进。首先,Tomcat线程池在启动时即预先创建全部核心线程,以应对启动初期的高并发请求。其次,通过重写阻塞队列的入队逻辑,Tomcat能够在任务数超过当前线程数但未达最大线程数时,及时创建非核心线程,而非等到队列满才行动。此外,Tomcat还引入了在拒绝策略触发后重新尝试入队的机制,以提高吞吐量。这些优化使得Tomcat线程池更适应IO密集型任务,有效提升了性能。
面对海量网络请求,Tomcat线程池如何进行扩展?
|
3月前
|
缓存 网络协议 Linux
扩展Linux网络栈
扩展Linux网络栈
71 3
|
4月前
|
存储 传感器 监控
智慧养殖的智慧网络:构建高效、可扩展的养殖生态
智慧养殖,在国家政策的大力扶持和农业数字化浪潮的推动下,正迅速发展。然而,许多人对它的价值仍持怀疑态度:认为智慧养殖只是昂贵的技术堆砌,短期内看不到经济回报,甚至怀疑其实用性。本文将挑战这些观点,展示智慧养殖如何通过技术整合提高效率、降低成本,并探讨如何克服网络稳定性和速度等技术障碍,引领养殖企业走向高效、经济的现代化转型。
260 22
|
4月前
|
域名解析 安全 物联网
阿里云EMAS HTTPDNS 扩展全球服务节点:提升解析安全性与网络覆盖
阿里云EMAS HTTPDNS新增国内西南、华南及国际欧洲、美东服务节点,提升了全球覆盖能力与性能。作为高效域名解析服务,EMAS HTTPDNS针对互联网、汽车、物流、IOT等行业提供支持,解决了传统解析易遭劫持等问题。新增节点优化了就近调度功能,显著缩短响应时间并增强了服务稳定性和连续性,尤其为中国企业的海外业务提供了强有力的支持。此次扩展展现了阿里云对服务质量的持续追求和全球市场布局的战略思考。
|
5月前
|
供应链 安全 区块链
区块链模块化:构建灵活、可扩展的未来网络
**区块链模块化**拆分系统为独立模块,提升**可扩展性**和**安全性**,增强**灵活性**,适应不同场景需求,如跨链互操作、行业定制和公共服务。模块化设计促进系统**定制化**,支持快速迭代,是区块链技术发展和创新的关键趋势。
|
5月前
|
数据采集 存储 中间件
Scrapy,作为一款强大的Python网络爬虫框架,凭借其高效、灵活、易扩展的特性,深受开发者的喜爱
【6月更文挑战第10天】Scrapy是Python的高效爬虫框架,以其异步处理、多线程及中间件机制提升爬取效率。它提供丰富组件和API,支持灵活的数据抓取、清洗、存储,可扩展到各种数据库。通过自定义组件,Scrapy能适应动态网页和应对反爬策略,同时与数据分析库集成进行复杂分析。但需注意遵守法律法规和道德规范,以合法合规的方式进行爬虫开发。随着技术发展,Scrapy在数据收集领域将持续发挥关键作用。
105 4
|
5月前
|
供应链 安全 区块链
区块链模块化:构建灵活、可扩展的未来网络
**区块链模块化**通过拆分系统为独立模块,如执行、结算、共识和数据层,提升**可扩展性**、**安全性和灵活性**。模块化允许定制化解决方案,适用于跨链互操作、行业特定需求及公共服务,如电子投票和版权保护。此方法降低耦合,增强安全性,为开发者创造更多创新机会,驱动区块链技术的未来发展方向。

热门文章

最新文章