模仿微博#話題#和@功能實現(xiàn)

因為項目中有類似微博的話題和@功能,所以我們來說說類似于新浪微博話題功能的實現(xiàn)颈畸,當文字是”#話題#”這種格式時,該文字字體的顏色得變成藍色。剛拿到這個內(nèi)容猜測的時候應(yīng)該用 UITextView 或 UITextField 去做,了解了思路就去百度了下,發(fā)現(xiàn)真的很少有這樣的案例,得知 YYKIt 大神的 demo 中有這樣的 demo? ?,于是就去下載看看, 這個 YYkit 的鏈接GitHub - ibireme/YYKit: A collection of iOS components.? ??


這個 demo 中有發(fā)布微博界面.


于是想偷懶把整個 copy 過來一下,不用重復(fù)造輪子


當我以為能用的時候我發(fā)現(xiàn),這個刪除是默認不能整體刪除的, YY 大神都是用正則表達式去匹配內(nèi)容,然后進行綁定和變色


于是我就想在這個基礎(chǔ)上看能不能改整體刪除,改了半天還是不行,就在github 上搜索, 找了好久都是標題黨,基本上都是模仿界面,根本沒有實質(zhì)性的內(nèi)容,于是就在谷歌上面搜索,找了好久還是不多

看了一下,發(fā)現(xiàn)新浪微博#話題#和@功能做的并不好,跟上面的情況一樣,仔細發(fā)現(xiàn),新浪微博#話題#和@功能雖然能變聲并不能整體刪除,這個我是測試過的,刪除#再輸入話題會出現(xiàn)正則匹配不正確的現(xiàn)象,@某人刪除文字時候點擊某人會出現(xiàn)查無此人顯現(xiàn), 不知道新浪微博測試和開放人員知不知道,YY 大神的 Demo 也是如如此,今天頭條的發(fā)布是整體刪除,給人感覺很好




于是就谷歌,最后終于找了一篇,

具體實現(xiàn)

在實現(xiàn)過程中并巍,我以AttributedString的顏色值為基準,用幾個正則為查找工具换途,結(jié)合UITextView的三個代理方法懊渡。

/// Prior to replacing text, this method is called to give your delegate a chance to accept or reject the edits. If you do not implement this method, the return value defaults to YES.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;

/// The text view calls this method in response to user-initiated changes to the text. This method is not called in response to programmatically initiated changes. Implementation of this method is optional.

- (void)textViewDidChange:(UITextView *)textView;

///? Implementation of this method is optional. You can use the selectedRange property of the text view to get the new selection.

- (void)textViewDidChangeSelection:(UITextView *)textView;


這三個代理方法

shouldChangeTextInRange 代理方法中刽射,第一,實現(xiàn)第一次選中剃执,第二次刪除功能誓禁;第二,實現(xiàn)插入話題后肾档,需要改變其他字符串的初始顏色摹恰,得在這個方法里面做個標志。

textViewDidChange 代理方法中怒见,實現(xiàn) 根據(jù) shouldChangeTextInRange 方法中所得到的標志俗慈,設(shè)置字符串的初始顏色;

textViewDidChangeSelection 代理方法中遣耍,實現(xiàn)讓光標不能移動到話題里面闺阱;

首先我定義了兩個變量,插入了話題以后舵变,繼續(xù)在后面輸入字符的話酣溃,字符顏色就跟話題顏色一樣了。所以纪隙,我得用這兩個變量來實現(xiàn)改變輸入字符的初始顏色赊豌。

/// 改變Range

@property (assign, nonatomic) NSRange changeRange;

/// 是否改變

@property (assign, nonatomic) BOOL isChanged;

哦,對了绵咱,我還得用一個變量來記錄上次光標所在的位置碘饼,因為話題字符串是不讓它輸入的。

/// 光標位置

@property (assign, nonatomic) NSInteger cursorLocation;

用戶從其他界面選擇好話題以后悲伶,它得插入到textview中鞍铡:

NSString *insertText = [NSString stringWithFormat:@"#%@#", dict[KeyTopicName]];

[self.textView insertText:insertText];

NSMutableAttributedString *tmpAString = [[NSMutableAttributedString alloc] initWithAttributedString:self.textView.attributedText];

[tmpAString setAttributes:@{ NSForegroundColorAttributeName: TopicColor, NSFontAttributeName: DefaultSizeFont } range:NSMakeRange(self.textView.selectedRange.location - insertText.length, insertText.length)];

self.textView.attributedText = tmpAString;

然后我還得找到將用戶所選擇插入的話題位置啊。

/**

*? 得到話題Range數(shù)組

*

*? @return return value description

*/

- (NSArray *)getTopicRangeArray:(NSAttributedString *)attributedString {

? ? NSAttributedString *traveAStr = attributedString ?: _textView.attributedText;

? ? __block NSMutableArray *rangeArray = [NSMutableArray array];

? ? static NSRegularExpression *iExpression;

? ? iExpression = iExpression ?: [NSRegularExpression regularExpressionWithPattern:@"#(.*?)#" options:0 error:NULL];

? ? [iExpression enumerateMatchesInString:traveAStr.string

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? options:0

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? range:NSMakeRange(0, traveAStr.string.length)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSRange resultRange = result.range;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSDictionary *attributedDict = [traveAStr attributesAtIndex:resultRange.location effectiveRange:&resultRange];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if ([attributedDict[NSForegroundColorAttributeName] isEqual:TopicColor]) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [rangeArray addObject:NSStringFromRange(result.range)];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }];

? ? return rangeArray;

}

那么拢切,三個UITextView delegate方法里的代碼就可以這么玩了:

#pragma mark - UITextView Delegate

- (void)textViewDidChangeSelection:(UITextView *)textView {

? ? NSArray *rangeArray = [self getTopicRangeArray:nil];

? ? BOOL inRange = NO;

? ? for (NSInteger i = 0; i < rangeArray.count; i++) {

? ? ? ? NSRange range = NSRangeFromString(rangeArray[i]);

? ? ? ? if (textView.selectedRange.location > range.location && textView.selectedRange.location < range.location + range.length) {

? ? ? ? ? ? inRange = YES;

? ? ? ? ? ? break;

? ? ? ? }

? ? }

? ? if (inRange) {

? ? ? ? textView.selectedRange = NSMakeRange(self.cursorLocation, textView.selectedRange.length);

? ? ? ? return;

? ? }

? ? self.cursorLocation = textView.selectedRange.location;

}

- (void)textViewDidChange:(UITextView *)textView {

? ? if (_isChanged) {

? ? ? ? NSMutableAttributedString *tmpAString = [[NSMutableAttributedString alloc] initWithAttributedString:self.textView.attributedText];

? ? ? ? [tmpAString setAttributes:@{ NSForegroundColorAttributeName: [UIColor blackColor], NSFontAttributeName: DefaultSizeFont } range:_changeRange];

? ? ? ? _textView.attributedText = tmpAString;

? ? ? ? _isChanged = NO;

? ? }

}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {

? ? if ([text isEqualToString:@""]) { // 刪除

? ? ? ? NSArray *rangeArray = [self getTopicRangeArray:nil];

? ? ? ? for (NSInteger i = 0; i < rangeArray.count; i++) {

? ? ? ? ? ? NSRange tmpRange = NSRangeFromString(rangeArray[i]);

? ? ? ? ? ? if ((range.location + range.length) == (tmpRange.location + tmpRange.length)) {

? ? ? ? ? ? ? ? if ([NSStringFromRange(tmpRange) isEqualToString:NSStringFromRange(textView.selectedRange)]) {

? ? ? ? ? ? ? ? ? ? // 第二次點擊刪除按鈕 刪除

? ? ? ? ? ? ? ? ? ? return YES;

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? // 第一次點擊刪除按鈕 選中

? ? ? ? ? ? ? ? ? ? textView.selectedRange = tmpRange;

? ? ? ? ? ? ? ? ? ? return NO;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? } else { // 增加

? ? ? ? NSArray *rangeArray = [self getTopicRangeArray:nil];

? ? ? ? if ([rangeArray count]) {

? ? ? ? ? ? for (NSInteger i = 0; i < rangeArray.count; i++) {

? ? ? ? ? ? ? ? NSRange tmpRange = NSRangeFromString(rangeArray[i]);

? ? ? ? ? ? ? ? if ((range.location + range.length) == (tmpRange.location + tmpRange.length) || !range.location) {

? ? ? ? ? ? ? ? ? ? _changeRange = NSMakeRange(range.location, text.length);

? ? ? ? ? ? ? ? ? ? _isChanged = YES;

? ? ? ? ? ? ? ? ? ? return YES;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? // 話題在第一個刪除后 重置text color

? ? ? ? ? ? if (!range.location) {

? ? ? ? ? ? ? ? _changeRange = NSMakeRange(range.location, text.length);

? ? ? ? ? ? ? ? _isChanged = YES;

? ? ? ? ? ? ? ? return YES;

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? return YES;

}


好吧,通過以上方法秆吵,基本輸入淮椰、刪除操作功能是實現(xiàn)了

最后是上傳, 上傳是本地先定義一個數(shù)組topicArray



然后在插入數(shù)據(jù)的時候往數(shù)組中插入一個對象


刪除數(shù)據(jù)的時候移除 topicArray 中的對象


最后上傳 textView的 text 內(nèi)容 和數(shù)組中的對象

顯示:

?1:YYLabel 顯示

?2:MLEmojiLabel 顯示

我是用了第二種MLEmojiLabel? ,YYLabel 沒有深入研究,性能比MLEmojiLabel要好,等不忙了再換,

因為我是上傳了文本內(nèi)容和對象給服務(wù)器,服務(wù)器給我類似的對象然后本地坐比對


,到此,爬坑算是結(jié)束了

代碼只是提供思路,沒有做封裝,也沒有深入的去優(yōu)化,希望用到的小伙伴能優(yōu)化并做的更好,謝謝

最后附上 demo?https://github.com/986138497/UITextView-

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纳寂,隨后出現(xiàn)的幾起案子主穗,更是在濱河造成了極大的恐慌,老刑警劉巖毙芜,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忽媒,死亡現(xiàn)場離奇詭異,居然都是意外死亡腋粥,警方通過查閱死者的電腦和手機晦雨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門架曹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闹瞧,你說我怎么就攤上這事绑雄。” “怎么了奥邮?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵万牺,是天一觀的道長。 經(jīng)常有香客問我洽腺,道長脚粟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任蘸朋,我火速辦了婚禮核无,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘度液。我一直安慰自己厕宗,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布堕担。 她就那樣靜靜地躺著已慢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霹购。 梳的紋絲不亂的頭發(fā)上佑惠,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音齐疙,去河邊找鬼膜楷。 笑死,一個胖子當著我的面吹牛贞奋,可吹牛的內(nèi)容都是我干的赌厅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼轿塔,長吁一口氣:“原來是場噩夢啊……” “哼特愿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勾缭,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤揍障,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后俩由,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毒嫡,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年幻梯,在試婚紗的時候發(fā)現(xiàn)自己被綠了兜畸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片努释。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膳叨,靈堂內(nèi)的尸體忽然破棺而出洽洁,到底是詐尸還是另有隱情,我是刑警寧澤菲嘴,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布饿自,位于F島的核電站,受9級特大地震影響龄坪,放射性物質(zhì)發(fā)生泄漏昭雌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一健田、第九天 我趴在偏房一處隱蔽的房頂上張望烛卧。 院中可真熱鬧,春花似錦妓局、人聲如沸总放。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽局雄。三九已至,卻和暖如春存炮,著一層夾襖步出監(jiān)牢的瞬間炬搭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工穆桂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宫盔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓享完,卻偏偏與公主長得像灼芭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子般又,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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