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

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

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

先来介绍一下我项目中的图文混排的需求:首先我从服务器中取到的数据是字符串,但是其中穿插图片的位置是一个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:]这个方法进行图片的渲染的,所以要达到我们的需要,我们需要对其进行一些简单的扩展:

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

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

2、在实现方法中添加如下代码,因为原文件有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。

时间: 2024-10-13 20:53:31

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

iOS开发swift版异步加载网络图片(带缓存和缺省图片)

iOS开发之swift版异步加载网络图片 与SDWebImage异步加载网络图片的功能相似,只是代码比较简单,功能没有SD的完善与强大,支持缺省添加图片,支持本地缓存. 异步加载图片的核心代码如下:  func setZYHWebImage(url:NSString?, defaultImage:NSString?, isCache:Bool){         var ZYHImage:UIImage?         if url == nil {             return   

iOS_第3方类库_EGOImageView异步加载网络图片

异步加载网络图片是很常见的需求 下载,导入,-fno-objc-arc 1.导入头文件 2.创建EGOImageView,并指定占位图,设置url即可 最终效果图:(后补) 附EGO原文件地址:

ios开发多线程篇--异步加载网络图片

一.异步加载网络图片 1.ATS (1)简介 从iOS9.0开始,如果按照以前的方式写代码,在访问网络的时候 ,会报以下警告信息: App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file. 原因:iOS9.0引入了新特性

Android之ListView异步加载网络图片(优化缓存机制)【转】

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa

Android 异步加载网络图片并缓存到本地

在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片. 软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取. 记得2月份在和爱奇艺公司的项目总监一起搞联通的OTT盒子的时候他就提了一下软引用,奇艺做的手机客户端就是采用这种方法,所以你会发现奇艺客户端占用很大的空间,下面就分享一下异步加载网络图片的方法吧. FileCache

Android批量图片加载经典系列——使用xutil框架缓存、异步加载网络图片

一.问题描述 为提高图片加载的效率,需要对图片的采用缓存和异步加载策略,编码相对比较复杂,实际上有一些优秀的框架提供了解决方案,比如近期在git上比较活跃的xutil框架 Xutil框架提供了四大模块: 1.  DbUtil模块:采用ORM机制简化Sqlite操作,一行代码就可执行增删改查.支持事务.支持延迟策略 2.  ViewUtils模块:可以说是Android的IOC框架,可以注解方式对ui.资源.事件进行绑定 3.  HttpUtils模块:支持同步.异步请求.支持大文件上传 4. 

cocos2dx lua中异步加载网络图片,可用于显示微信头像

最近在做一个棋牌项目,脚本语言用的lua,登录需要使用微信登录,用户头像用微信账户的头像,微信接口返回的头像是一个url,那么遇到的一个问题就是如何在lua中异步加载这个头像,先在引擎源码里找了下可能会提供这个功能的地方,发现好像没有提供类似功能,那么只能自己动手写.所以我在ImageView这个类里面添加了一个成员方法,其实可以不写在ImageView里,而且我觉得非必需情况下还是不要修改引擎源码的好,因为如果源码改动比较多的话,将来引擎版本升级会比较麻烦.我写在ImageView里纯粹是想偷

android 安卓异步加载网络图片,与viewpager结合使用示例

[1]异步加载图片类AsyncImageLoader package com.example.testdddleapk.cus; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.

Android异步加载网络图片

Android图片的异步加载,主要原理: 加载图片时先查看缓存中时候存在该图片,如果存在则返回该图片,否则先加载载一个默认的占位图片,同时创建一个通过网络获取图片的任务并添加,任务完成后放松消息给主线程更新界面. 使用方法: [java] view plain copy AsynImageLoader asynImageLoader = new AsynImageLoader(); asynImageLoader.showImageAsyn(imageView, imageUrl, resId)