环信IM聊天页面搭建

0. cell 的id 可以用代码注册 也可以在storyboard中注册

1. cell 的创建 identifier


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    //判断数据源类型
    if ([self.dataSources[indexPath.row] isKindOfClass:[NSString class]]) {//显示时间cell
        XMGTimeCell *timeCell = [tableView dequeueReusableCellWithIdentifier:@"TimeCell"];
        timeCell.timeLabel.text = self.dataSources[indexPath.row];
        return timeCell;
    }
    
    //1.先获取消息模型
    EMMessage *message = self.dataSources[indexPath.row];
    //    EMMessage
    /* from:xmgtest1 to:xmgtest7 发送方(自己)
     * from:xmgtest7 to:xmgtest1 接收方 (好友)
     */
    
    XMGChatCell *cell = nil;
    if ([message.from isEqualToString:self.buddy.username]) {//接收方
        cell = [tableView dequeueReusableCellWithIdentifier:ReceiverCell];
    }else{//发送方
        cell = [tableView dequeueReusableCellWithIdentifier:SenderCell];
    }
    //显示内容
    cell.message = message;
    
    return cell;
    
    
}

1.5 labe 只用设置leading 和 top 约束

注意labe 只用设置leading 和 top 约束,Trading 和bottom 是根据内容来的

2. 设置label自动换行

Label.numbersOfLines= 0;
Label preferred width = 345;

3. 设置背景imageView 和 label 的frame 相同

选中两个控件 四边距对齐
Leading edges
Trading edges
Top edges
Bottom edges
全部为0

4、设置背景图片合理拉伸 (聊天背景泡泡)

Stretching
X y width height
0 0 1 1
改为
0.5 0.7 0 0

5、 messageImgeView

设置messageImgeView 上下左右 比 label 的frame 外拉伸一点
设置constrain 约束

6.不同聊天内容格式的处理


-(void)setMessage:(EMMessage *)message{

    //重用时,把聊天图片控件移除
    [self.chatImgView removeFromSuperview];
    
    _message = message;
    
    // 1.获取消息体
    id body = message.messageBodies[0];
    if ([body isKindOfClass:[EMTextMessageBody class]]) {//文本消息
        EMTextMessageBody *textBody = body;
        self.messageLabel.text = textBody.text;
    }else if([body isKindOfClass:[EMVoiceMessageBody class]]){//语音消息

        self.messageLabel.attributedText = [self voiceAtt];
    }else if([body isKindOfClass:[EMImageMessageBody class]]){//图片消息
        [self showImage];
    }
    else{
        self.messageLabel.text = @"未知类型";
    }
    

}

7.处理语音

#pragma mark 返回语音富文本
-(NSAttributedString *)voiceAtt{
    // 创建一个可变的富文本
    NSMutableAttributedString *voiceAttM = [[NSMutableAttributedString alloc] init];
    
    // 1.接收方: 富文本 = 图片 + 时间
    if ([self.reuseIdentifier isEqualToString:ReceiverCell]) {
        // 1.1接收方的语音图片
        UIImage *receiverImg = [UIImage imageNamed:@"chat_receiver_audio_playing_full"];
        
        // 1.2创建图片附件
        NSTextAttachment *imgAttachment = [[NSTextAttachment alloc] init];
        imgAttachment.image = receiverImg;
        imgAttachment.bounds = CGRectMake(0, -7, 30, 30);
        // 1.3图片富文本
        NSAttributedString *imgAtt = [NSAttributedString attributedStringWithAttachment:imgAttachment];
        [voiceAttM appendAttributedString:imgAtt];
        
        // 1.4.创建时间富文本
        // 获取时间
        EMVoiceMessageBody *voiceBody = self.message.messageBodies[0];
        NSInteger duration = voiceBody.duration;
        NSString *timeStr = [NSString stringWithFormat:@"%ld'",duration];
        NSAttributedString *timeAtt = [[NSAttributedString alloc] initWithString:timeStr];
        [voiceAttM appendAttributedString:timeAtt];
        
    }else{
    // 2.发送方:富文本 = 时间 + 图片
        // 2.1 拼接时间
        // 获取时间
        EMVoiceMessageBody *voiceBody = self.message.messageBodies[0];
        NSInteger duration = voiceBody.duration;
        NSString *timeStr = [NSString stringWithFormat:@"%ld'",duration];
        NSAttributedString *timeAtt = [[NSAttributedString alloc] initWithString:timeStr];
        [voiceAttM appendAttributedString:timeAtt];
        
        
        // 2.1拼接图片
        UIImage *receiverImg = [UIImage imageNamed:@"chat_sender_audio_playing_full"];
        
        // 创建图片附件
        NSTextAttachment *imgAttachment = [[NSTextAttachment alloc] init];
        imgAttachment.image = receiverImg;
        imgAttachment.bounds = CGRectMake(0, -7, 30, 30);
        // 图片富文本
        NSAttributedString *imgAtt = [NSAttributedString attributedStringWithAttachment:imgAttachment];
        [voiceAttM appendAttributedString:imgAtt];
        
    }
    
    return [voiceAttM copy];

}

8.处理图片


-(void)showImage{
    
    // 获取图片消息体
    EMImageMessageBody *imgBody = self.message.messageBodies[0];
    CGRect thumbnailFrm = (CGRect){0,0,imgBody.thumbnailSize};

    
//    CGRect thumbnailFrm = (CGRect){0,0,imgBody.size};
    
    // 设置Label的尺寸足够显示UIImageView
    NSTextAttachment *imgAttach = [[NSTextAttachment alloc] init];
    imgAttach.bounds = thumbnailFrm;
    NSAttributedString *imgAtt = [NSAttributedString attributedStringWithAttachment:imgAttach];
    self.messageLabel.attributedText = imgAtt;
    
    //1.cell里添加一个UIImageView
    [self.messageLabel addSubview:self.chatImgView];
    
    //2.设置图片控件为缩略图的尺寸
    self.chatImgView.frame = thumbnailFrm;
    
    //3.下载图片
//    NSLog(@"thumbnailLocalPath %@",imgBody.thumbnailLocalPath);
//    NSLog(@"thumbnailRemotePath %@",imgBody.thumbnailRemotePath);
    NSFileManager *manager = [NSFileManager defaultManager];
    // 如果本地图片存在,直接从本地显示图片
    UIImage *palceImg = [UIImage imageNamed:@"downloading"];
    if ([manager fileExistsAtPath:imgBody.thumbnailLocalPath]) {
#warning 本地路径使用fileURLWithPath方法
        [self.chatImgView sd_setImageWithURL:[NSURL fileURLWithPath:imgBody.thumbnailLocalPath] placeholderImage:palceImg];
    }else{
        // 如果本地图片不存,从网络加载图片
        [self.chatImgView sd_setImageWithURL:[NSURL URLWithString:imgBody.thumbnailRemotePath] placeholderImage:palceImg];
    }
    
    
}

9.发送类型的两种cell 可以 使用同一个类,id不同就可以了

10.设置行高

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    //时间cell的高度是固定
    if ([self.dataSources[indexPath.row] isKindOfClass:[NSString class]]) {
        return 18;
    }
    
    // 设置label的数据
    // 1.获取消息模型
    EMMessage *msg = self.dataSources[indexPath.row];
    
    self.chatCellTool.message = msg;
//    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];
    return [self.chatCellTool cellHeghit];
}

/** 返回cell的高度*/
-(CGFloat)cellHeghit{
    //1.重新布局子控件
    [self layoutIfNeeded];
    
    return 5 + 10 + self.messageLabel.bounds.size.height + 10 + 5;

}

10.5注意接受好友回复的时候是谁回复的

11.加载本地聊天记录

-(void)loadLocalChatRecords{
    //假设在数组的第一位置添加时间
//    [self.dataSources addObject:@"16:06"];
    
    // 要获取本地聊天记录使用 会话对象
    EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:self.buddy.username conversationType:eConversationTypeChat];
    self.conversation = conversation;
    
    // 加载与当前聊天用户所有聊天记录
    NSArray *messages = [conversation loadAllMessages];

    // 添加到数据源
//    [self.dataSources addObjectsFromArray:messages];
    for (EMMessage *msgObj in messages) {
        [self addDataSourcesWithMessage:msgObj];
    }
}


12.输入框高度计算

#pragma mark - UITextView代理 --发送文字
-(void)textViewDidChange:(UITextView *)textView{
    
//    NSLog(@"contentOffset %@",NSStringFromCGPoint(textView.contentOffset));
    // 1.计算TextView的高度,
    CGFloat textViewH = 0;
    CGFloat minHeight = 33;//textView最小的高度
    CGFloat maxHeight = 68;//textView最大的高度
    
    // 获取contentSize的高度
    CGFloat contentHeight = textView.contentSize.height;
    if (contentHeight < minHeight) {
        textViewH = minHeight;
    }else if (contentHeight > maxHeight){
        textViewH = maxHeight;
    }else{
        textViewH = contentHeight;
    }
    
   
    
    // 2.监听Send事件--判断最后的一个字符是不是换行字符
    if ([textView.text hasSuffix:@"\n"]) {
        NSLog(@"发送操作");
        [self sendText:textView.text];
        
        // 清空textView的文字
        textView.text = nil;
        
        // 发送时,textViewH的高度为33
        textViewH = minHeight;
        
    }
    
    // 3.调整整个InputToolBar 高度
    self.inputToolBarHegihtConstraint.constant = 6 + 7 + textViewH;
    // 加个动画
    [UIView animateWithDuration:0.25 animations:^{
        [self.view layoutIfNeeded];
    }];
    
    
    // 4.记光标回到原位
#warning 技巧
    [textView setContentOffset:CGPointZero animated:YES];
    [textView scrollRangeToVisible:textView.selectedRange];
}


你可能感兴趣的:(环信IM聊天页面搭建)