| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- //
- // MentionTextView.m
- // AIIM
- //
- // Created by qitewei on 2025/5/30.
- //
- #import "MentionTextView.h"
- @implementation MentionTextView{
- NSMutableArray<NSValue *> *_mentionRanges;
- }
- - (NSArray<NSValue *> *)mentionRanges {
- return [_mentionRanges copy];
- }
- - (void)setMentionRanges:(NSArray<NSValue *> *)mentionRanges {
- _mentionRanges = [mentionRanges mutableCopy];
- }
- - (void)setup {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(textDidChange:)
- name:UITextViewTextDidChangeNotification
- object:self];
- [self detectMentions];
- }
- - (void)textDidChange:(NSNotification *)notification {
- [self detectMentions];
- }
- - (void)detectMentions {
- // 支持中文、字母、数字、下划线和连字符
- NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"@[\\w\\u4e00-\\u9fa5-]+" options:0 error:nil];
- NSArray *matches = [regex matchesInString:self.text options:0 range:NSMakeRange(0, self.text.length)];
-
- NSMutableArray *ranges = [NSMutableArray array];
- for (NSTextCheckingResult *match in matches) {
- [ranges addObject:[NSValue valueWithRange:match.range]];
- }
- self.mentionRanges = ranges;
- }
- - (BOOL)deleteMentionAtCursorPosition {
- NSRange selectedRange = self.selectedRange;
- if (selectedRange.location == 0) return NO;
- // 找出包含光标前一个位置的所有mention
- NSMutableArray *candidateMentions = [NSMutableArray array];
- for (NSValue *rangeValue in _mentionRanges) {
- NSRange mentionRange = [rangeValue rangeValue];
- if (NSLocationInRange(selectedRange.location - 2, mentionRange)) {
- [candidateMentions addObject:rangeValue];
- }
- }
- if (candidateMentions.count == 0) return NO;
- // 找出最合适的mention(取范围最大的)
- NSValue *bestMatch = candidateMentions.firstObject;
- for (NSValue *rangeValue in candidateMentions) {
- if ([rangeValue rangeValue].length > [bestMatch rangeValue].length) {
- bestMatch = rangeValue;
- }
- }
-
- NSRange deleteRange = [bestMatch rangeValue];
- NSString *deletedMention = [self.text substringWithRange:deleteRange];
-
- // 先保存原始索引
- NSUInteger originalIndex = [_mentionRanges indexOfObject:bestMatch];
- // 执行删除
- NSMutableString *text = [self.text mutableCopy];
- [text deleteCharactersInRange:deleteRange];
- self.text = text;
-
- // 更新selectedRange
- self.selectedRange = NSMakeRange(deleteRange.location, 0);
-
- // 更新其他mention的范围
- [self updateMentionRangesAfterDeletion:deleteRange];
- // 回调
- if (self.mentionDeleteHandler) {
- self.mentionDeleteHandler(deletedMention, originalIndex);
- }
-
- return YES;
- }
- - (void)updateMentionRangesAfterDeletion:(NSRange)deletedRange {
- NSMutableArray *updatedRanges = [NSMutableArray array];
- for (NSValue *rangeValue in _mentionRanges) {
- NSRange range = [rangeValue rangeValue];
-
- if (NSEqualRanges(range, deletedRange)) {
- continue; // 跳过被删除的
- }
-
- if (range.location > deletedRange.location) {
- range.location -= deletedRange.length;
- }
- [updatedRanges addObject:[NSValue valueWithRange:range]];
- }
- _mentionRanges = updatedRanges;
- }
- - (void)deleteMentionAtIndex:(NSUInteger)index {
- if (index >= _mentionRanges.count) return;
-
- NSValue *rangeValue = _mentionRanges[index];
- NSRange deleteRange = [rangeValue rangeValue];
- NSString *deletedMention = [self.text substringWithRange:deleteRange];
-
- // 执行删除
- NSMutableString *text = [self.text mutableCopy];
- [text deleteCharactersInRange:deleteRange];
- self.text = text;
-
- // 更新selectedRange
- self.selectedRange = NSMakeRange(deleteRange.location, 0);
-
- // 更新其他mention的范围
- [self updateMentionRangesAfterDeletion:deleteRange];
-
- // 回调
- if (self.mentionDeleteHandler) {
- self.mentionDeleteHandler(deletedMention, index);
- }
- }
- - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- UITouch *touch = [touches anyObject];
- CGPoint location = [touch locationInView:self];
-
- UITextPosition *position = [self closestPositionToPoint:location];
- NSUInteger index = [self offsetFromPosition:self.beginningOfDocument toPosition:position];
-
- for (NSValue *rangeValue in self.mentionRanges) {
- NSRange mentionRange = [rangeValue rangeValue];
- if (NSLocationInRange(index, mentionRange)) {
- if(self.text.length>=(mentionRange.location+mentionRange.length)){
- NSString *mention = [self.text substringWithRange:mentionRange];
- if (self.mentionTapHandler) {
- self.mentionTapHandler(mention);
- }
- }
- return;
- }
- }
-
- [super touchesEnded:touches withEvent:event];
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- @end
|