擴展於RCLabel的支持異步加載網絡圖片的富文本引擎的設計

擴展於RCLabel的支持異步加載網絡圖片的富文本引擎的設計

        在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

相關文章
相關標籤/搜索