Habber - IOS XMPP 客户端 教程 (续)对方输入状态显示

Is typing...


Train of thought

要显示对方输入状态,也就是说要给对方发送一个标志,对方接收到这个标志,就知道你正在输入,然后在标题栏上显示你正在输入就行了。

那怎么发送标志呢?知道了我们传输的信息都是XML文件,也就是要接收两个不同的状态。增加一个标记composing,假如我们输入的时候它就传递isTyping,不输入的时候什么都不传就好了。


Do it!

OK, 有了思路我们就着手去做。

  1. 首先我得知道我们什么时候正在输入什么时候停止输入,而且我们知道输入框是一个UITextView,由于真正的控件调用都是框架做好了的,我们要进入框架。

  2. 找到UUInputFunctionView.h,好啊,我们看到了定义成UITextView的*TextViewInput这个小东西,接着进入m文件中去!

  3. 在m文件中我们发现TextViewDelegate已经接收了代理,- (void)textViewDidBeginEditing:(UITextView *)textView- (void)textViewDidEndEditing:(UITextView *)textView,我们需要的正是他们!

  4. 太好了找到了能够发现输入状态变更的方法,我们就该让它们为我们提供服务了!
    改框架:UUInputFunctionView.h中@Protocol中我们增加两个方法 - (void)composing;- (void)endComposing;,添加好后我们就要把钥匙交给代理了。

  5. 交接,UUInputFunctionView.m
    - (void)textViewDidBeginEditing:(UITextView *)textView
    {
    placeHold.hidden = self.TextViewInput.text.length > 0;
    [self.delegate composing];
    }


    - (void)textViewDidEndEditing:(UITextView *)textView
    {
    placeHold.hidden = self.TextViewInput.text.length > 0;
    [self.delegate endComposing];
    }

  6. 实现代理:回到我们UUChatViewController.m中,增加两个方法:- (void)composing {}- (void)endComposing {},方法内容先留空,接下来我们要大改了。

  7. 首先,改变发送XML的结构:

#pragma mark - 发送XML封装数据
- (void)sendXML:(NSString *)message image:(UIImage *)img voice:(NSData *)voice time:(NSUInteger)second isComposing:(NSString *)status{
    //生成xml
    //<composing>
    NSXMLElement *composing = [NSXMLElement elementWithName:@"composing"];
    [composing setStringValue:status];
    //<body>
    NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
    [body setStringValue:message];
    //<message>
    NSXMLElement *mes = [NSXMLElement elementWithName:@"message"];
    //<message type = chat>
    [mes addAttributeWithName:@"type" stringValue:@"chat"];
    //<message type = "chat" to = _chatUserName>
    [mes addAttributeWithName:@"to" stringValue:_chatUserName];
    //<message type = "chat" to = _chatUserName from = ...>
    [mes addAttributeWithName:@"from" stringValue:[[NSUserDefaults standardUserDefaults] stringForKey:USERID]];
    //<message ...><composing></composing><body></body></message>
    [mes addChild:composing];
    [mes addChild:body];

    if (img) {
        NSData *imgData = UIImageJPEGRepresentation(img, 0.1);
        NSString *imgStr=[imgData base64EncodedStringWithOptions:0];

        //<message ...><body></body><img></img></message>
        NSXMLElement *imgAttachment = [NSXMLElement elementWithName:@"image"];
        [imgAttachment setStringValue:imgStr];
        [mes addChild:imgAttachment];
    }

    if (voice) {
        NSString *voiceStr = [voice base64EncodedStringWithOptions:0];
        NSXMLElement *voiceAttachment = [NSXMLElement elementWithName:@"voice"];
        [voiceAttachment setStringValue:voiceStr];
        [voiceAttachment addAttributeWithName:@"voiceTime" unsignedIntegerValue:second];
        [mes addChild:voiceAttachment];
    }

    //发送消息
    [[self xmppStream] sendElement:mes];
    NSLog(@"%@", mes);
}

发送结构改好了,我们就可以填充实现代理的方法了:

- (void)composing {
    [self sendXML:@"" image:nil voice:nil time:0 isComposing:@"isTyping"];
}

- (void)endComposing {
    [self sendXML:@"" image:nil voice:nil time:0 isComposing:@""];
}

我们还要更改接受的配置:

//收到消息后把消息传递给代理
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    //解析xml
    NSString *composing = [[message elementForName:@"composing"] stringValue];
    composing = !composing ? @"" : composing;
    NSString *msg = [[message elementForName:@"body"] stringValue];
    msg = !msg ? @"" : msg;
    NSString *img = [[message elementForName:@"image"] stringValue];
    img = !img ? @"" : img;
    NSString *voice = [[message elementForName:@"voice"] stringValue];
    NSString *voiceTime = [[[message elementForName:@"voice"] attributeForName:@"voiceTime"] stringValue];
    if (!voice) {
        voice = @"";
        voiceTime = @"";
    }
    NSString *from = [[message attributeForName:@"from"] stringValue];

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:composing forKey:@"composing"];
    [dict setObject:msg forKey:@"msg"];
    [dict setObject:img forKey:@"photo"];
    [dict setObject:voice forKey:@"voice"];
    [dict setObject:voiceTime forKey:@"voiceTime"];
    [dict setObject:from forKey:@"sender"];

    [_messageDelegate newMessageReceived:dict];
}

这样我们能够接收到输入状态了,我们还需要对接收过来的数据进行处理:

- (void)newMessageReceived:(NSDictionary *)messageContent {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *dic = [NSDictionary dictionary];
        NSString *composing = [messageContent objectForKey:@"composing"];
        NSString *msg = [messageContent objectForKey:@"msg"];
        NSString *imageStr = [messageContent objectForKey:@"photo"];
        NSString *voiceStr = [messageContent objectForKey:@"voice"];
        NSString *voiceTimeStr = [messageContent objectForKey:@"voiceTime"];
        NSString *from = [messageContent objectForKey:@"sender"];
        if (imageStr.length > 0) {
            NSData *imgData = [[NSData alloc] initWithBase64EncodedString:imageStr options:0];
            UIImage *image = [UIImage imageWithData:imgData];
            dic = @{@"picture": image,
                    @"type": @(UUMessageTypePicture),
                    @"sender": from};
        } else if (voiceStr.length > 0) {
            NSData *voiceData = [[NSData alloc] initWithBase64EncodedString:voiceStr options:0];
            dic = @{@"voice": voiceData,
                    @"strVoiceTime": voiceTimeStr,
                    @"type": @(UUMessageTypeVoice),
                    @"sender": from};
        } else {
            dic = @{@"strContent": msg,
                    @"type": @(UUMessageTypeText),
                    @"sender": from};
        }

        if (![composing isEqualToString:@"isTyping"]) {
            [self dealTheFunctionData:dic];
            self.navigationItem.title = _chatUserName;
        } else {
            self.navigationItem.title = @"Is typing...";
        }
    });
}

这里需要注意,如果我们接收过来的是 文本,图片还有音频都为空,只有标志为”isTyping”的文本,为了防治cell显示接收到的空字符,我们还要加以过滤:

- (void)dealTheFunctionData:(NSDictionary *)dic
{
    if (![[dic objectForKey:@"strContent"] isEqualToString:@""]) {
        [self.chatModel addSpecifiedItem:dic];
        [self.chatTableView reloadData];
        [self tableViewScrollToBottom];
    }
}

好了,现在我们能够在聊天窗口显示“Is typing…”的状态了,但是我们还需要在“好友列表”中加一层过滤,不然只要接收到信息它就会显示一条未读信息,对方只是改变输入状态它都会显示一条未读信息,这样是不行的,来到“FriendListTableViewController.m”中,我们要改变其接收和显示的规则:

- (void)newMessageReceived:(NSDictionary *)messageContent {
    NSDictionary *dic = [NSDictionary dictionary];
    NSString *composing = [messageContent objectForKey:@"composing"];
    NSString *msg = [messageContent objectForKey:@"msg"];
    NSString *imageStr = [messageContent objectForKey:@"photo"];
    NSString *voiceStr = [messageContent objectForKey:@"voice"];
    NSString *voiceTimeStr = [messageContent objectForKey:@"voiceTime"];
    NSString *from = [messageContent objectForKey:@"sender"];
    if (imageStr.length > 0) {
        NSData *imgData = [[NSData alloc] initWithBase64EncodedString:imageStr options:0];
        UIImage *image = [UIImage imageWithData:imgData];
        dic = @{@"picture": image,
                @"type": @(UUMessageTypePicture),
                @"sender": from};
    } else if (voiceStr.length > 0) {
        NSData *voiceData = [[NSData alloc] initWithBase64EncodedString:voiceStr options:0];
        dic = @{@"voice": voiceData,
                @"strVoiceTime": voiceTimeStr,
                @"type": @(UUMessageTypeVoice),
                @"sender": from};
    } else {
        dic = @{@"strContent": msg,
                @"type": @(UUMessageTypeText),
                @"sender": from};
    }
    //重点来了~
    if ((![composing isEqualToString:@"isTyping"] && ![msg isEqualToString:@""]) || ![imageStr isEqualToString:@""] || ![voiceStr isEqualToString:@""]) {
        //收到消息数组
        [_messages addObject:dic];
        //每次刷新表格,就可以看到有多少条未读信息
        [self.tableView reloadData];
    }
}

OK!我们改变了它的规则,只要是”isTyping”都会被过滤掉!

好了,对方输入状态的显示的功能有了,改了我两个多小时,博客居然写了快一个小时!It’s wired…but, whatever.

改起来有些繁琐,但也算是对之前发送接收消息一个小的应用,不难理解,注意一些过滤规则就是了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值