UILabel、UITextView、M80AttributedLabel、YYLabel的簡單對比

這周在做消息頁面的文本消息展示時(shí),遇到了選擇什么樣的控件去展示文本消息的問題。

在一個(gè)消息列表中,相比于圖片,語音等類型的消息,文本消息是最常見的,但是文本消息的展示也是最復(fù)雜的。在文本消息中包含多種信息,比如鏈接,電話號碼等等特殊的字符。不僅要在UI展示上對這些特殊字符進(jìn)行處理,也就是富文本的展示,還要對其設(shè)置相應(yīng)的點(diǎn)擊事件。

UILabel和UITextView

對于常見的系統(tǒng)控件UILabel和UITextView,都可以實(shí)現(xiàn)富文本的展示。

區(qū)別在于:

1、UITextView有系統(tǒng)相應(yīng)的代理方法可以對鏈接字符和電話字符處理相應(yīng)的點(diǎn)擊事件。而UILabel沒有這樣的功能。

2、UITextView和UILabel都可以實(shí)現(xiàn)自動(dòng)換行。由于UILabel不可編輯,也不可滑動(dòng)。而UITextView繼承自UIScrollView,是可編輯的,也是可滑動(dòng)。但是UITextView在展示時(shí),距離上下左右都分別有8px的距離,因此使用計(jì)算字符串長度和高度的方法 [NSString sizeWithFont:constrainedToSize:lineBreakMode:]時(shí),需要注意這些邊距細(xì)節(jié)的加減。因此,UILabel在展示消息時(shí)可以更方便的計(jì)算自適應(yīng)高度,而UITextView會(huì)比較麻煩一些。

M80AttributedLabel

這個(gè)自定義的控件,是這周在看網(wǎng)易云信的源碼時(shí)學(xué)習(xí)到的。

M80AttributedLabel是一個(gè)繼承自UIView的控件,實(shí)現(xiàn)了label的基本功能外,還封裝了一些富文本展示的方法,可以自動(dòng)的檢測鏈接,設(shè)置鏈接的排版樣式,以及相應(yīng)的點(diǎn)擊事件的代理方法。

在這里著重看了M80AttributedLabel如何實(shí)現(xiàn)點(diǎn)擊事件的過程。

1、根據(jù)UIView的觸摸代理方法獲取到當(dāng)前觸摸點(diǎn)的位置坐標(biāo);

2、根據(jù)當(dāng)前文本的frame,得到frame所對應(yīng)的行數(shù)組( CFArrayRef)及每行的原點(diǎn)坐標(biāo)數(shù)組;

3、遍歷行數(shù)組,通過一系列矩陣變換和位置操作,取得當(dāng)前點(diǎn)擊區(qū)域的文字在整段文字中的索引;

4、在正則匹配到的URL數(shù)組中(該數(shù)組的每個(gè)元素存儲(chǔ)了URL及其對應(yīng)的位置),查找該索引所對應(yīng)的URL;

5、找到對應(yīng)的URL后,就會(huì)通過safari打開該鏈接。

下面是使用M80AttributedLabel的一個(gè)小demo:

- (void)setM80AttributedLabelText

{

? ? NSString *string1 = @"第一條文本消息https://www.baidu.com";

? ? [self.m80Label setText:string1];

}

#pragma mark - M80AttributedLabelDelegate

- (void)m80AttributedLabel:(M80AttributedLabel *)label

? ? ? ? ? ? clickedOnLink:(id)linkData{

? ? NSString *link = (NSString *)linkData;

? ? NSLog(@"%@", link);


? ? NSURLComponents *components = [[NSURLComponents alloc] initWithString:link];

? ? if (components)

? ? {

? ? ? ? if (!components.scheme)

? ? ? ? {

? ? ? ? ? ? //默認(rèn)添加 http

? ? ? ? ? ? components.scheme = @"http";

? ? ? ? }

? ? ? ? [[UIApplication sharedApplication] openURL:[components URL]];

? ? }

}

#pragma mark - getter/setter

- (M80AttributedLabel *)m80Label

{

? ? if (!_m80Label) {

? ? ? ? _m80Label = [[M80AttributedLabel alloc] initWithFrame:CGRectMake(100, 60, 100, 100)];

? ? ? ? _m80Label.numberOfLines = 0;

? ? ? ? _m80Label.lineBreakMode = NSLineBreakByWordWrapping;

? ? ? ? _m80Label.backgroundColor = [UIColor clearColor];

? ? ? ? _m80Label.autoresizingMask = UIViewAutoresizingFlexibleWidth;

? ? ? ? _m80Label.textAlignment = kCTTextAlignmentLeft;

? ? ? ? _m80Label.font = [UIFont systemFontOfSize:16];

? ? ? ? _m80Label.textColor = [UIColor blackColor];

? ? ? ? _m80Label.highlightColor = [UIColor redColor];

? ? ? ? _m80Label.linkColor = [UIColor yellowColor];

? ? ? ? _m80Label.underLineForLink = NO;

? ? ? ? _m80Label.userInteractionEnabled = YES;

? ? ? ? _m80Label.delegate = self;

? ? }

? ? return _m80Label;

}

YYLabel

YYLabel也是一個(gè)繼承自UIView的自定義控件,是YYKit下的一部分。據(jù)說YYKit很強(qiáng)大,但是目前用到的還只是其中的YYLabel,更強(qiáng)大的功能,下來再慢慢挖掘。

YYLabel同樣封裝了設(shè)置富文本,排版,樣式等方法和屬性,同時(shí),還封裝了方法通過block來實(shí)現(xiàn)點(diǎn)擊事件。

- (void)yy_setTextHighlightRange:(NSRange)range

? ? ? ? ? ? ? ? ? ? ? ? ? color:(nullable UIColor *)color

? ? ? ? ? ? ? ? backgroundColor:(nullable UIColor *)backgroundColor

? ? ? ? ? ? ? ? ? ? ? ? userInfo:(nullable NSDictionary *)userInfo

? ? ? ? ? ? ? ? ? ? ? tapAction:(nullable YYTextAction)tapAction

? ? ? ? ? ? ? ? longPressAction:(nullable YYTextAction)longPressAction;

下面是使用YYLabel實(shí)現(xiàn)富文本展示的demo:

- (void)setupYYLabelText:(NSString *)plainText

{

? ? NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString: plainText];

? ? attributeStr.yy_font = [UIFont boldSystemFontOfSize:12];

? ? NSRange range1 = [plainText rangeOfString:@"www.baidu.com"];

? ? [attributeStr yy_setTextUnderline:[YYTextDecoration decorationWithStyle:YYTextLineStyleSingle] range:range1];

? ? [attributeStr yy_setFont:[UIFont boldSystemFontOfSize:12] range:range1];

? ? UIColor *textColor1 = [UIColor redColor];

? ? UIColor *tapedBackgroundColor1 = [UIColor grayColor];

? ? [attributeStr yy_setTextHighlightRange:range1 color:textColor1 backgroundColor:tapedBackgroundColor1 tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {

? ? ? ? //點(diǎn)擊跳轉(zhuǎn)鏈接

? ? ? ? NSString *link = @"www.baidu.com";

? ? ? ? NSURLComponents *components = [[NSURLComponents alloc] initWithString:link];

? ? ? ? if (components)

? ? ? ? {

? ? ? ? ? ? if (!components.scheme)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? components.scheme = @"http";

? ? ? ? ? ? }

? ? ? ? ? ? [[UIApplication sharedApplication] openURL:[components URL]];

? ? ? ? }

? ? }];

? ? NSRange range2 = [plainText rangeOfString:@"188XXXXXXXX"];

? ? [attributeStr yy_setTextUnderline:[YYTextDecoration decorationWithStyle:YYTextLineStyleSingle] range:range2];

? ? [attributeStr yy_setFont:[UIFont boldSystemFontOfSize:12] range:range2];


? ? UIColor *textColor2 = [UIColor redColor];

? ? UIColor *tapedBackgroundColor2 = [UIColor grayColor];


? ? [attributeStr yy_setTextHighlightRange:range2 color:textColor2 backgroundColor:tapedBackgroundColor2 tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {//點(diǎn)擊提示是否要打電話

? ? ? ? NSString *phone = @"188XXXXXXXX";

? ? ? ? NSLog(@"%@", phone);

? ? ? ? NSMutableString * str=[[NSMutableString alloc] initWithFormat:@"tel:%@",phone];

? ? ? ? [[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];

? ? }];


? ? self.yyLabel.attributedText = attributeStr;

}

#pragma mark - getter/setter

- (YYLabel *)yyLabel

{

? ? if (!_yyLabel)

? ? {

? ? ? ? _yyLabel = [[YYLabel alloc] init];

? ? ? ? _yyLabel.frame = CGRectMake(20, 100, self.view.frame.size.width-40, 300);

? ? ? ? _yyLabel.textAlignment = NSTextAlignmentCenter;

? ? ? ? _yyLabel.textVerticalAlignment = YYTextVerticalAlignmentCenter;

? ? ? ? _yyLabel.numberOfLines = 0;

? ? ? ? _yyLabel.backgroundColor = [UIColor colorWithWhite:0.933 alpha:1.000];

? ? }

? ? return _yyLabel;

}

在我們展示消息列表時(shí),還需要自適應(yīng)的去計(jì)算YYLabel的高度,計(jì)算方法如下:

CGFloat width = [[UIScreen mainScreen] bounds].size.width;

YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:CGSizeMake(width - 81, CGFLOAT_MAX) text:attributeStr];

self.height = layout.textBoundingSize.height;

在開發(fā)過程中,用YYLabel來展示文本消息,但是在展示的過程中發(fā)現(xiàn),YYLabel的點(diǎn)擊事件并不響應(yīng),通過查找代碼打印日志,發(fā)現(xiàn)YYLabel在觸發(fā)觸摸事件的時(shí),按照touchesBegan->touchesMoved->touchesCancelled的順序走的代碼,但是點(diǎn)擊事件的響應(yīng)是在touchesEnded方法中。而發(fā)生這種情況的原因是YYLabel的父視圖有一個(gè)點(diǎn)擊手勢UITapGestureRecognizer,父視圖的手勢識(shí)別了點(diǎn)擊之后,子視圖的觸摸就會(huì)被取消。解決的辦法是:將父視圖的點(diǎn)擊手勢UITapGestureRecognizer的屬性cancelsTouchesInView設(shè)置為NO,這樣父視圖在識(shí)別了手勢之后,還會(huì)把點(diǎn)擊事件傳遞給其他視圖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容