美文网首页
iOS仿照微信@功能实现

iOS仿照微信@功能实现

作者: colhy | 来源:发表于2021-05-14 15:59 被阅读0次

大致思路

  1. 创建MXPointAtManager类把@功能封装在一起,新增功能模块与原代码尽量解耦。
  2. 输入@符号,弹出群成员列表,选择成员
  3. 删除@成员,输入框要同时把成员跟@符号一起删除
  4. 监听方法如下,该代理方法有range可以定位,replacementText可以判断是插入、删除。
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
  • MXPointAtManager对外的API

///当前是否有@信息
@property (nonatomic, assign, readonly) BOOL havedAt;
///返回当前@信息里的userId
@property (nonatomic, strong, readonly) NSArray *userIdsArr;
///插入@
- (void)pointAtFriend:(MXInputTextView *)textView inRange:(NSRange)range;
///删除@
- (BOOL)delPointAt:(MXInputTextView *)textView withRange:(NSRange)range ;
///清空@信息
- (void)clearAtMessage;

MXInputTextView 继承 YYTextView类

  • 输入@符号

if ([@"@" isEqualToString:text]) {
  ///群聊才有@功能
  [[MXPointAtManager sharedManager] pointAtFriend:self.chatToolBar.inputTextView inRange:range]; 
}

判断是否进入选择@的人页面

- (void)pointAtFriend:(MXInputTextView *)textView inRange:(NSRange)range {
    [textView resignFirstResponder];
    //选择完后回调
    void (^selectBlock)(NSArray *) = ^(NSArray *friendsArr) {
        ///name: 名称 userID: 对应用户ID
        [self addPointAt:textView inRange:range withName:name andUserID:obj.userid];
    };
    NSArray *tempArr = 排序后的群成员列表(移除自己);
    NSDictionary *param = @{@"dataSourceArr":tempArr,
                            @"selectedBlock":selectBlock};
    ///跳转选择列表
    MXRoute(@"ChooseContactAtVC", param);
}

选择@的群友后的处理,拼接[@群友名称],保存[@群友名称]的NSRange,以便之后删除操作。
把textView.text根据range 分隔成两块frontText、behindText,在frontText拼上当前@信息,再重新拼接赋值给textView 设置光标位置

- (void)addPointAt:(MXInputTextView *)textView inRange:(NSRange)range  withName:(NSString *)nickname andUserID:(NSString *)userID{
    NSString *text = textView.text;
    NSString *frontText = [text substringToIndex:range.location+1];
    NSString *behindText = @"";
    if (text.length >= range.location + 1) {
        behindText = [text substringFromIndex:range.location + 1];
    }
    frontText = StrF(@"%@%@ ", frontText, nickname);
    if ([StringUtil isEmpty:nickname]) {
        frontText = StrF(@"%@%@", frontText, nickname);
    }
    NSString *atName = StrF(@"%@%@ ", @"@", nickname);
    if ([StringUtil isEmpty:nickname]) {
        atName = StrF(@"%@%@", @"@", nickname);
    }
    NSRange inRange = [frontText rangeOfString:atName options:NSBackwardsSearch];
    if (inRange.location == NSNotFound) {
        return;
    }
    textView.text = StrF(@"%@%@", frontText, behindText);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //改变光标的位置
        NSRange range = NSMakeRange(inRange.location + inRange.length, 0);
        textView.selectedRange = range;
        [textView becomeFirstResponder];
    });
    if ([StringUtil isEmpty:userID]) {
        return;
    }
    //pointAtDataMDic pointAtRangeMDic 保存着同一个key
    [self.pointAtDataMDic setValue:nickname?:@"" forKey:userID];
    [self.pointAtRangeMDic setValue:userID forKey:NSStringFromRange(inRange)];
}
  • 删除@成员

把textView.text根据range 分隔成两块frontText、behindText,在frontText查找@相关信息,查找到后删除,再重新拼接赋值给textView,设置光标位置

- (BOOL)delPointAt:(MXInputTextView *)textView withRange:(NSRange)range {
    if (textView.text.length < (range.location + 1)) {
        return YES;
    }
    NSString *subText = [textView.text substringToIndex:range.location + 1];
    //删除的字符是否是 ' '
    if (!([subText characterAtIndex:subText.length-1] == ' ')) {
        return YES;
    }
    NSInteger index = -1;
    for(NSInteger i = subText.length - 1; i >= 0; i--){
        if ([subText characterAtIndex:i] == '@' ) {
            index = i;
            break;
        }
    }
    if (index == -1) {
        return YES;
    }
    NSRange rang = NSMakeRange(index, subText.length - index);
    NSString *rangeString = NSStringFromRange(rang);
    if (![self.pointAtRangeMDic.allKeys containsObject:rangeString]) {
        return YES;
    }
    NSString *userID = self.pointAtRangeMDic[rangeString];
    [self.pointAtDataMDic removeObjectForKey:userID];
    [self.pointAtRangeMDic removeObjectForKey:rangeString];
    //从光标处分隔
    NSString *text = textView.text;
    NSString *frontText = [text substringToIndex:range.location+1];
    NSString *behindText = @"";
    if (text.length >= range.location + 1) {
        behindText = [text substringFromIndex:range.location + 1];
    }
    frontText = [frontText substringToIndex:rang.location];
    NSRange inRange = [textView.text rangeOfString:frontText options:NSBackwardsSearch];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //改变光标的位置
        textView.text = StrF(@"%@%@", frontText, behindText);
        NSRange range = NSMakeRange(inRange.location + inRange.length, 0);
        textView.selectedRange = range;
        [textView becomeFirstResponder];
    });
    return NO;
}
  • 输入框发送的时候判断当前是否有@信息,有的话就组装到Message信息中去

if ([MXPointAtManager sharedManager].havedAt) {
  ///组装相关Message
}
///发送完记得清楚本次@信息
[[MXPointAtManager sharedManager] clearAtMessage];
  • 会话列表数据库,增加isAt字段,存储是否有@自己的信息。接受到信息后把@自己的信息持久化到本地。根据这个字段显示类似微信[有人@我]的提示信息

相关文章

网友评论

      本文标题:iOS仿照微信@功能实现

      本文链接:https://www.haomeiwen.com/subject/ihckjktx.html