iOS開發(fā)—自定義可交互的UITextView

最近有個項目需要做一個可以對textView內(nèi)容進行交互的功能,因此做了一個類似微博展示Emotion豹绪、@somebody、#話題#以及鏈接的Demo申眼。


一瞒津、工具

1、RegexKitLitegithub.com/samdeane/RegexKitLite

正則表達括尸,使用起來是非常方便巷蚪,由于是MAC模式,在使用的時候濒翻,需要進行以下操作:

使用 -fno-objc-arc 讓RegexKitLite支持ARC

2屁柏、導入libicucore.tbd動態(tài)庫

2、MJExtension https://github.com/CoderMJLee/MJExtension

字典和模型之間互相轉換的超輕量級框架有送。

二前联、Demo結構

通過創(chuàng)建自定義的statusTextView展示帶有屬性的特殊字段內(nèi)容:鏈接、Emotion娶眷、話題以及@somebody等等似嗤。

?自定義TextView(statusTextView)

model

* specialPart

* status

* TZTextPart

tool

-?TZEmotionTool

-?TZEmotion

三、代碼解讀

1届宠、首先創(chuàng)建要展示的內(nèi)容(截取一段微博正文):

`@"@StephenCurry? “I'm Back”烁落!https://bbs.hupu.com (使用#秒拍#錄制,免流量看熱門短視頻M阕ⅰ) #庫里經(jīng)典比# 去年季后賽次輪伤塌,傷愈復出的庫里首戰(zhàn)面對開拓者就拿下40分9籃板8助攻,加時賽瘋砍17分轧铁,率隊逆轉獲勝晉級西決每聪。#StreeBall#? [吃元宵][吃元宵][吃元宵]";`

2、實例化展示內(nèi)容

在TZStatus頭文件聲明屬性

/** 正文內(nèi)容 */

@property (copy, nonatomic) NSString *contentText;

/** 帶屬性的微博信息內(nèi)容 */

@property (strong, nonatomic) NSAttributedString *attributedText;


在TZTextPart頭文件聲明屬性

/** 文字段內(nèi)容 */

@property (strong, nonatomic) NSString *partText;

/** 文字段范圍 */

@property (assign, nonatomic) NSRange range;

/** 是否是特殊文字 */

@property (assign, nonatomic, getter=isSpecial) BOOL special;

/** 是否是表情文字 */

@property (assign, nonatomic, getter=isEmotion) BOOL emotion;


在TZSpecialPart頭文件聲明屬性

/** 特殊段內(nèi)容 */

@property (strong, nonatomic) NSString *specialText;

/** 特殊段范圍 */

@property (assign, nonatomic) NSRange specialRange;

/** 特殊文字的矩形框 數(shù)組 */

@property (strong, nonatomic) NSArray *rects;

通過正則表達將NSString中的 “表情”齿风、“@somebody”药薯、“#話題#”、“鏈接”救斑、“普通字段” 區(qū)分開童本,并拼接成NSAttributedString:

- (NSAttributedString *)attributedTextWithText:(NSString *)contentText{

//? ? 利用contentText生成attributedText

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];

//? ? 1.RegexKitLite正則表達方法

//? ? 表情的規(guī)則

NSString *emotionPattern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";

//? ? @的規(guī)則

NSString *atPattern = @"@[0-9a-zA-Z\\u4e00-\\u9fa5_-]+";

//? ? #話題#的規(guī)則

NSString *topicPattern = @"#[0-9a-zA-Z\\u4e00-\\u9fa5]+#";

//? ? url鏈接的規(guī)則

NSString *urlPattern = @"\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^[:punct:]\\s]|/)))";

NSString *pattern = [NSString stringWithFormat:@"%@|%@|%@|%@", emotionPattern, atPattern, topicPattern, urlPattern];

//? ? 各種文字段的內(nèi)容

NSMutableArray *parts = [NSMutableArray array];

//? ? 2.遍歷所有內(nèi)容 選出特殊字段內(nèi)容

[contentText enumerateStringsMatchedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {

//? ? ? ? 沒有匹配的字段

if ((*capturedRanges).length == 0) return;

//? ? ? ? 收集特殊字段

TZTextPart *part = [[TZTextPart alloc] init];

part.partText = *capturedStrings;

part.range = *capturedRanges;

part.special = YES;

part.emotion = [part.partText hasPrefix:@"["] && [part.partText hasSuffix:@"]"];

[parts addObject:part];

}];

//? ? 3.遍歷所有內(nèi)容 選出普通字段內(nèi)容

[contentText enumerateStringsSeparatedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {

//? ? ? ? 沒有匹配的字段

if ((*capturedRanges).length == 0) return;

//? ? ? ? 收集普通字段

TZTextPart *part = [[TZTextPart alloc] init];

part.partText = *capturedStrings;

part.range = *capturedRanges;

[parts addObject:part];

}];

//? ? 4.將獲得的所有字段按 range 排序

[parts sortUsingComparator:^NSComparisonResult(TZTextPart? *_Nonnull part1, TZTextPart *_Nonnull part2) {//升序排列

if (part1.range.location > part2.range.location) {

return NSOrderedDescending;

}

return NSOrderedAscending;

}];

UIFont *font = [UIFont systemFontOfSize:15.0];

//? ? ? 儲存特殊屬性數(shù)組

NSMutableArray *specials = [NSMutableArray array];

//? ? 5.分別處理各文字段 設置內(nèi)容的屬性

for (TZTextPart *part in parts) {

NSAttributedString *substr = nil;

if (part.isEmotion) {//表情

NSTextAttachment *attch = [[NSTextAttachment alloc] init];

NSString *name = [TZEmotionTool emotionWithChs:part.partText].png;

if (name) { // 能找到對應的圖片

attch.image = [UIImage imageNamed:name];

attch.bounds = CGRectMake(0, -3, font.lineHeight, font.lineHeight);

substr = [NSAttributedString attributedStringWithAttachment:attch];

} else { // 表情圖片不存在

substr = [[NSAttributedString alloc] initWithString:part.partText];

}

}else if (part.special){//特殊文字

substr = [[NSAttributedString alloc] initWithString:part.partText attributes:@{

NSForegroundColorAttributeName:[UIColor blueColor]

}];

//? ? ? ? ? ? 將特殊文字段的 內(nèi)容 和 位置 保存起來

TZSpecialPart *specialPart = [[TZSpecialPart alloc] init];

specialPart.specialText = part.partText;

NSUInteger loc = part.range.location;

NSUInteger len = part.range.length;

specialPart.specialRange = NSMakeRange(loc, len);

[specials addObject:specialPart];

}else{//非特殊文字

substr = [[NSAttributedString alloc] initWithString:part.partText];

}

[attributedText appendAttributedString:substr];

}

[attributedText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, attributedText.length)];

//? ? 把specials 添加到? 0,1 的位置上(第一個字符的屬性上)

[attributedText addAttribute:@"specials" value:specials range:NSMakeRange(0, 1)];

return attributedText;

}

3脸候、在收集到特殊字段數(shù)組后穷娱,在自定義的textView中顯示出來绑蔫,并創(chuàng)建相應字段的點擊事件。

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event方法可以判斷是否響應textView內(nèi)的touch時間泵额。

/**

告訴系統(tǒng):觸摸點point是否在這個UI控件身上

*/

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{

[self setupSpecialRects];

// ?找出被觸摸的特殊字符串

TZSpecialPart *specialPart = [self touchingSpecialWithPoint:point];

if (specialPart) {//觸摸到特殊字符串時才響應touch事件

return YES;

}else{

return NO;

}

}

/**

*? 找出被觸摸的特殊字符串

*/

-(TZSpecialPart *)touchingSpecialWithPoint:(CGPoint)point

{

NSArray *specials = [self.attributedText attribute:@"specials" atIndex:0 effectiveRange:nil];

for (TZSpecialPart *specialPart in specials){

for (NSValue *rectValue in specialPart.rects) {

//? ? ? ? ? ? 如果手指位置在 特定文字 位置

if(CGRectContainsPoint(rectValue.CGRectValue,point)){

return specialPart;

}

}

}

return nil;

}

點擊時尋找特殊字符串配深,并顯示出來

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event{

//? ? 1.獲取觸摸位置

UITouch *touch = [touches anyObject];

CGPoint point = [touch locationInView:self];

//? ? 2.初始化特殊文字段的矩形框

[self setupSpecialRects];

//? ? 3.根據(jù)觸摸點獲得被觸摸的特殊字符串

TZSpecialPart *specialPart = [self touchingSpecialWithPoint:point];

//? ? 4.在被觸摸的特殊字符串后面顯示一段高亮的背景

for (NSValue *rectValue in specialPart.rects) {

//? ? ? 添加遮蓋

UIView *cover = [[UIView alloc] init];

cover.backgroundColor = [UIColor greenColor];

cover.frame = rectValue.CGRectValue;

cover.tag = TZCoverTag;

[self insertSubview:cover atIndex:0];

}

}

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嫁盲,隨后出現(xiàn)的幾起案子篓叶,更是在濱河造成了極大的恐慌,老刑警劉巖亡资,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異向叉,居然都是意外死亡锥腻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門母谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘦黑,“玉大人,你說我怎么就攤上這事奇唤⌒页猓” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵咬扇,是天一觀的道長甲葬。 經(jīng)常有香客問我,道長懈贺,這世上最難降的妖魔是什么经窖? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮梭灿,結果婚禮上画侣,老公的妹妹穿的比我還像新娘。我一直安慰自己堡妒,他們只是感情好配乱,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著皮迟,像睡著了一般搬泥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伏尼,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天佑钾,我揣著相機與錄音,去河邊找鬼烦粒。 笑死休溶,一個胖子當著我的面吹牛代赁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兽掰,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芭碍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孽尽?” 一聲冷哼從身側響起窖壕,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杉女,沒想到半個月后瞻讽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡熏挎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年速勇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坎拐。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡烦磁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哼勇,到底是詐尸還是另有隱情都伪,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布积担,位于F島的核電站陨晶,受9級特大地震影響,放射性物質發(fā)生泄漏帝璧。R本人自食惡果不足惜珍逸,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望聋溜。 院中可真熱鬧谆膳,春花似錦、人聲如沸撮躁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽把曼。三九已至杨帽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗤军,已是汗流浹背注盈。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叙赚,地道東北人老客。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓僚饭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胧砰。 傳聞我的和親對象是個殘疾皇子鳍鸵,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容