iOS中@功能的完整實現
點選上方“iOS開發”,選擇“置頂公眾號”
關鍵時刻,第一時間送達!
哼哼想不到吧,我又回來啦!好久沒寫文章了,以後儘量多寫寫吧。最近看到有人問@功能的需求,就大概寫了寫,先看看實現效果:
效果圖
這個功能的具體要求如下:
1、一個@是由一個@字元和一個空格字元包起來的。
2、支援手寫輸入,只要符合就高亮顯示。
3、支援從列表選擇,選擇後插入游標所在位置並高亮。
4、游標不能出現在一個@詞中間,點選中間後自動移動到@詞後面,長按滑動游標時也要越過@詞。但是當用戶長按選擇文字時可以。
5、當游標正好在一個@詞後面時,按刪除鍵@詞要整體刪除。
先附上本文demo(https://github.com/lisongrc/ATDemo),算下來程式碼也沒有多少,還算簡潔,大家一看就懂。其中包括的功能:
1、輸入框@編輯和選擇功能,也就是上面那些需求。
2、輸入框隨著文字多少改變高度,並根據鍵盤隨動。
3、釋出後顯示在列表上,並將符合的@高亮顯示。
4、列表上的cell根據文字自動計算高度。
5、點選高亮詞後可以捕獲到事件,自己實現跳轉就可以。好了,下面大概講解一下,有不明白的地方可以下載demo具體看看。
用到的第三方
1、HPGrowingTextView(https://github.com/HansPinckaers/GrowingTextView),用來實現輸入框根據文字改變高度。使用和UITextView類似,代理也和UITextView差不多:
HPGrowingTextViewDelegate
2、MLLabel,用來高亮顯示label文字中的某些文字,支援自動識別一些常見的,也可以自定義規則。支援連結色和點選色等等一些配置。點選回撥裡面自己實現跳轉就可以。
MLLabel
整合這些第三方用的是cocoapods,關於cocoapods的教程可以看我的這篇文章;
具體實現的一些細節
1、檢驗文字中所有的@詞
用的是系統的NSRegularExpression類,不熟悉的大家可以去查一下,這裡就不細講了:
- (NSArray<NSTextCheckingResult *> *)findAllAt
{
// 找到文字中所有的@
NSString *string = self.growingTextView.text;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:kATRegular options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *matches = [regex matchesInString:string options:NSMatchingReportProgress range:NSMakeRange(0, [string length])];
return matches;
}
2、輸入框根據輸入文字多少自動改變高度
在HPGrowingTextView的代理裡面實現:
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height
{
self.commentViewHeight.constant = height + 14;
}
3、輸入框中的文字要隨著文字改變實時將@詞高亮
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView
{
UITextRange *selectedRange = growingTextView.internalTextView.markedTextRange;
NSString *newText = [growingTextView.internalTextView textInRange:selectedRange];
if (newText.length < 1)
{
// 高亮輸入框中的@
UITextView *textView = self.growingTextView.internalTextView;
NSRange range = textView.selectedRange;
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:textView.text];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, string.string.length)];
NSArray *matches = [self findAllAt];
for (NSTextCheckingResult *match in matches)
{
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(match.range.location, match.range.length - 1)];
}
textView.attributedText = string;
textView.selectedRange = range;
}
}
首先判斷是不是正在選擇文字,不是的話我們才應該處理。然後就是用正則找到所有的@詞,用NSMutableAttributedString的方法加上高亮色,然後把最終的attributedString賦值給TextView,並將游標的位置復原為替換文字之前的狀態。
4、刪除時@詞要整體刪除
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text isEqualToString:@""])
{
NSRange selectRange = growingTextView.selectedRange;
if (selectRange.length > 0)
{
//使用者長按選擇文字時不處理
return YES;
}
// 判斷刪除的是一個@中間的字元就整體刪除
NSMutableString *string = [NSMutableString stringWithString:growingTextView.text];
NSArray *matches = [self findAllAt];
BOOL inAt = NO;
NSInteger index = range.location;
for (NSTextCheckingResult *match in matches)
{
NSRange newRange = NSMakeRange(match.range.location + 1, match.range.length - 1);
if (NSLocationInRange(range.location, newRange))
{
inAt = YES;
index = match.range.location;
[string replaceCharactersInRange:match.range withString:@""];
break;
}
}
if (inAt)
{
growingTextView.text = string;
growingTextView.selectedRange = NSMakeRange(index, 0);
return NO;
}
}
//判斷是回車鍵就傳送出去
if ([text isEqualToString:@"
"])
{
[self.comments addObject:growingTextView.text];
self.growingTextView.text = @"";
[self.growingTextView resignFirstResponder];
[self.tableView reloadData];
return NO;
}
return YES;
}
首先判斷替換詞是空字串就代表是刪除操作,然後找出輸入框文字中所有的@詞,判斷要刪除的字元是否在任意一個@詞中間,如果在就把輸入框文字中這個@詞整體刪除,然後重新賦值給TextView,並糾正游標的位置。但是要判斷使用者在長按選擇文字時不處理。
5、游標不能點選落在一個@詞中間:
- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView
{
// 游標不能點落在@詞中間
NSRange range = growingTextView.selectedRange;
if (range.length > 0)
{
// 選擇文字時可以
return;
}
NSArray *matches = [self findAllAt];
for (NSTextCheckingResult *match in matches)
{
NSRange newRange = NSMakeRange(match.range.location + 1, match.range.length - 1);
if (NSLocationInRange(range.location, newRange))
{
growingTextView.internalTextView.selectedRange = NSMakeRange(match.range.location + match.range.length, 0);
break;
}
}
}
其實就是判斷游標改變位置後是否在@詞中間,如果在就把游標強制移動到@詞後面。但是當用戶長按選擇文字時可以。
6、從列表中選擇人去@他
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// 去選擇@的人
[self.growingTextView.internalTextView unmarkText];
NSInteger index = self.growingTextView.text.length;
if (self.growingTextView.isFirstResponder)
{
index = self.growingTextView.selectedRange.location + self.growingTextView.selectedRange.length;
[self.growingTextView resignFirstResponder];
}
SelectUserController *atVC = segue.destinationViewController;
atVC.selectBlock = ^(NSString *name)
{
UITextView *textView = self.growingTextView.internalTextView;
NSString *insertString = [NSString stringWithFormat:kATFormat,name];
NSMutableString *string = [NSMutableString stringWithString:textView.text];
[string insertString:insertString atIndex:index];
self.growingTextView.text = string;
[self.growingTextView becomeFirstResponder];
textView.selectedRange = NSMakeRange(index + insertString.length, 0);
};
}
其實就是選擇後將@詞插入到游標位置,並將游標糾正到@詞後面。
7、評論列表cell上的@高亮並可點選。使用MLLabel實現起來還是比較簡單的:
- (void)setComment:(NSString *)comment
{
_comment = comment;
self.titleLabel.text = comment;
// 高亮@
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:kATRegular options:NSRegularExpressionCaseInsensitive error:nil];
[regex enumerateMatchesInString:comment options:NSMatchingReportProgress range:NSMakeRange(0, comment.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop)
{
[self.titleLabel addLinkWithType:MLLinkTypeUserHandle value:comment range:result.range];
}];
}
self.titleLabel.didClickLinkBlock = ^(MLLink *link, NSString *linkText, MLLinkLabel *label)
{
NSLog(@"點選了%@",linkText);
};
8、cell高度自動計算,系統自己支援,不瞭解的可以看我的這篇文章(https://www.jianshu.com/p/64f0e1557562)
好了,大概就是這麼些東西,是不是很簡單呢,如果還有不明白的地方就下載本文demo仔細看看吧。
(https://github.com/lisongrc/ATDemo)
作者:iOS_小松哥
連結:https://www.jianshu.com/p/eabf5a944158
iOS開發整理髮布,轉載請聯絡作者獲得授權