美文网首页
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