亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS App開發中擴展RCLabel組件進行基于HTML的文本布局

2020-07-26 03:18:23
字體:
來源:轉載
供稿:網友

iOS系統是一個十分注重用戶體驗的系統,在iOS系統中,用戶交互的方案也十分多,然而要在label中的某部分字體中添加交互行為確實不容易的,如果使用其他類似Button的控件來模擬,文字的排版又將是一個解決十分困難的問題。這個問題的由來是項目中的一個界面中有一些廣告位標簽,而這些廣告位的標簽卻是嵌在文本中的,當用戶點擊文字標簽的位置時,會跳轉到響應的廣告頁。
CoreText框架和一些第三方庫可以解決這個問題,但直接使用CoreText十分復雜,第三方庫多注重于富文本的排版,對類似文字超鏈接的支持亦不是特別簡潔,我們可以借助一些第三方的東西進行針對性更強,更易用的封裝。
RCLabel是一個第三方的將html字符串進行文本布局的工具,代碼十分輕巧,并且其是基于CoreText框架的,其原生性和擴展性十分強。

一、擴展于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];
                                        });
                           
                                    }
                                  
                                }
                               
                            };
                           
                        });
                    }                
                   
                }

二、視圖類與模型類的設計
RCLabel的核心之處在于將HTML文本轉換為富文本布局視圖,因此我們可以將要顯示的文本編程html字符串,將其可以進行用戶交互的部分進行html超鏈接關聯,RCLabel就檢測到我們點擊的區域進行響應邏輯的回調。設計類如下:
.h文件
//文本與超鏈接地址關聯的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
上面我們有用到一個YHBaseLinkingLabelModel類,這個類進行了鏈接與字符的映射,設計如下:
@interface YHBaseLinkingLabelModel : YHBaseModel
/**
 *文字內容
 */
@property(nonatomic,strong)NSString * text;
/**
 *超鏈接地址 nil則為無
 */
@property(nonatomic,strong)NSString * linking;
@end
YHBaseHtmlView類是對RCLabel的一層封裝,其中也對RCLabel進行了一些優化和改動,代碼較多且在上篇博客中有介紹,這里不再多做解釋了。
在ViewController中寫如下代碼進行使用:
- (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);
}
運行效果如下:

201671291423648.jpg (825×575)

效果不錯,并且十分簡單易用,對吧。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品毛片网大全| 日韩一区二区精品视频| 8050国产精品久久久久久| 日韩网站在线观看| 日本精品久久电影| 97av在线播放| 亚洲国产欧美一区二区丝袜黑人| 亚洲欧美日韩图片| 一夜七次郎国产精品亚洲| 日韩美女视频免费在线观看| 亚洲美女性生活视频| 欧美疯狂xxxx大交乱88av| 国语自产精品视频在线看| 久久九九全国免费精品观看| 亚洲综合视频1区| 亚洲精品xxx| 亚洲图片在线综合| 欧美黑人xxx| 精品国内产的精品视频在线观看| 欧美做爰性生交视频| 91亚洲精品久久久| 日韩av免费网站| 国产精品99久久久久久白浆小说| 66m—66摸成人免费视频| 久久精品国产亚洲精品2020| 欧美xxxwww| 亚洲美女又黄又爽在线观看| 91精品久久久久久久久久久久久久| 国产精品免费小视频| 色av吧综合网| 欧美亚洲日本黄色| 日本精品久久久久久久| 中文字幕欧美日韩| 亚洲热线99精品视频| 国产精品福利网站| 国产热re99久久6国产精品| 色系列之999| 中文字幕在线成人| 国产大片精品免费永久看nba| 91久久在线观看| 成人福利在线视频| 亚洲国产精品大全| 成人午夜黄色影院| 亚洲精品电影在线| 久久精品国产91精品亚洲| 日本午夜人人精品| 色综合天天狠天天透天天伊人| 日韩在线观看免费av| 高跟丝袜欧美一区| 欧美福利视频网站| 久久久亚洲福利精品午夜| 久久久在线观看| 亚洲精品国精品久久99热一| 欧美日韩国产丝袜另类| 国产精品永久免费观看| 国内免费精品永久在线视频| 午夜精品视频在线| 亚洲欧洲日本专区| 日韩视频精品在线| 欧美激情久久久| 一本色道久久88精品综合| 日韩成人中文字幕| 精品福利一区二区| 欧美在线视频a| 国产精品久久久久久搜索| 国产精品久久久久久久久男| 精品久久久久久久大神国产| 成人精品一区二区三区电影黑人| 精品国产一区二区三区久久狼黑人| 在线视频日韩精品| 51午夜精品视频| 成人激情视频在线| 国产精品主播视频| 92福利视频午夜1000合集在线观看| 欧美国产日韩一区二区在线观看| 最近中文字幕日韩精品| 最近2019中文字幕在线高清| 欧美日韩一区免费| 欧美孕妇毛茸茸xxxx| 久久久免费在线观看| 欧美激情成人在线视频| 久久久久www| 欧美成人午夜激情| 日韩av综合中文字幕| 美女999久久久精品视频| 久久福利网址导航| 欧美激情aaaa| 欧美孕妇与黑人孕交| 日韩国产激情在线| 久久久中精品2020中文| 成人妇女淫片aaaa视频| 亚洲va欧美va国产综合剧情| 国产一区二区三区在线播放免费观看| 国产日韩欧美91| 91精品国产99久久久久久| 久久精品美女视频网站| 亚洲aa中文字幕| 久久香蕉频线观| 欧美性猛交xxxx偷拍洗澡| 欧美巨乳在线观看| 一区二区成人av| 992tv在线成人免费观看| 日韩精品电影网| 国产日韩欧美在线看| 欧美一级大片视频| 欧美成人免费小视频| 精品国产鲁一鲁一区二区张丽| 日韩视频免费观看| 欧美精品情趣视频| 欧美精品福利在线| 91亚洲精品视频| 日韩精品极品在线观看| 欧美成aaa人片在线观看蜜臀| 国产91露脸中文字幕在线| 永久免费毛片在线播放不卡| 亚洲的天堂在线中文字幕| 激情亚洲一区二区三区四区| 久久综合伊人77777尤物| 精品国产乱码久久久久久天美| 亚洲国产精品电影| 亚洲精品福利资源站| 国产精品美女免费| 久久久久久久一区二区| 中文字幕日韩av| 91久久久国产精品| 国产日韩欧美中文| 最好看的2019的中文字幕视频| 国内外成人免费激情在线视频网站| 亚洲一级免费视频| 777精品视频| 久久久999成人| 精品亚洲一区二区三区在线播放| 成人激情视频免费在线| 国产精品1234| 91国内免费在线视频| 91成人在线播放| 精品一区二区电影| 亚洲精品久久7777777| 欧美激情a∨在线视频播放| 久久不射热爱视频精品| 日韩美女激情视频| 国产精品极品在线| 在线观看国产成人av片| 一个色综合导航| 亚洲欧美国产制服动漫| 欧美精品少妇videofree| 欧洲亚洲女同hd| 国产精品露脸av在线| 亚洲欧美三级在线| 日韩精品在线观看网站| 亚洲欧美在线免费| 久久久久久亚洲精品中文字幕| 青青草原一区二区| 欧洲成人性视频| 亚洲成**性毛茸茸| 欧美激情啊啊啊| 欧美激情在线观看视频| 欧美韩国理论所午夜片917电影| 亚洲国产成人精品久久| 在线观看国产精品日韩av| 久久久久国产精品www| 亚洲欧美色图片| 在线观看欧美www| 91免费高清视频|