项目中集成了环信即时通讯,但是项目需要自定义消息类型,看环信发送消息方法,在发送消息的时候可以附加自定义的内容。
下面我将拿微信中名片为例来介绍:
确定发送方式:
首先需要与Android开发人员沟通发送什么类型消息的时候传递,环信sdk中封装的任何消息都是可以附加自定义内容的,在这里我们定义的是在发送文本消息的时候传递,也就是说发送自定义的名片等于发送的是文本消息。
确定字段:
先看自定义消息中所显示的内容:头像、昵称、效应号;我们定义的字典字段为:nickname、user_pic、num这三个,由于在点击这条消息的时候需要跳转到这个人的个人信息页面,所有又应该加上user_id,我们项目中所自定义的 消息不只一种还有其他的消息,这样我们又需要加上一个type来区分,最终附加字段为: nickname、user_pic、num、user_id、type
发送消息:
在选择完联系人后,回调信息到聊天页面发送消息
NSDictionary *dict = @{@"user_id":user_id,@"nickname":nickname,@"user_pic":user_pic,@"num":number,@"type":@"0"};
[self sendTextMessage:@"[效应名片]" withExt:dict];
定义UI
每条消息都是显示都是一个Cell,Cell要继承EaseBaseMessageCell,聊天的Cell都是有气泡的,显示的信息都是在气泡上,也就是说,我们只需要定义一个View然后放到气泡上,并且修改气泡的大小,就可以了。
- 定义UI页面
创建一个创建一个继承UIView的类,在这个类上定义自己需要的UI,也就是下图所显示的内容
下面是我定义的LCChatXiaoYingCardView.m代码
@interface LCChatXiaoYingCardView ()
/**
头像
*/
@property (strong, nonatomic) UIImageView *iconImageView;
/**
昵称
*/
@property (strong, nonatomic) UILabel *nameLabel;
/**
效应号
*/
@property (strong, nonatomic) UILabel *numberLabel;
@end
@implementation LCChatXiaoYingCardView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self loadView];
}
return self;
}
- (void)loadView{
_iconImageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 5, 30, 30)];
[self addSubview:_iconImageView];
self.nameLabel = [[UILabel alloc]initWithFrame:CGRectMake(50, 5, 100, 15)];
_nameLabel.font = [UIFont systemFontOfSize:13];
[self addSubview:self.nameLabel];
_numberLabel = [[UILabel alloc]init];
[self addSubview:_numberLabel];
_numberLabel.font = [UIFont systemFontOfSize:12];
_numberLabel.textColor = [UIColor grayColor];
[self.numberLabel makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_iconImageView.right).offset(10);
make.bottom.equalTo(_iconImageView.bottom).offset(0);
make.width.offset(100);
}];
UIView *lineView = [[UIView alloc]initWithFrame:CGRectMake(0, 45, 180, 0.5)];
lineView.backgroundColor = [UIColor groupTableViewBackgroundColor];
[self addSubview:lineView];
UILabel *myLabel = [[UILabel alloc]init];
[self addSubview:myLabel];
myLabel.text = @"效应名片";
[myLabel makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(lineView.bottom).offset(0);
make.left.equalTo(_iconImageView.left);
make.height.offset(15);
make.width.offset(50);
}];
myLabel.font = [UIFont systemFontOfSize:11];
}
- (void)setExtInfo:(LCChatExtModel *)extInfo
{
[_iconImageView sd_setImageWithURL:[NSURL URLWithString:extInfo.user_pic] placeholderImage:[UIImage imageNamed:@"image"]];
_nameLabel.text = extInfo.nickname;
_numberLabel.text = [NSString stringWithFormat:@"效应号:%@",extInfo.num];
}
@end
- 自定义Cell
创建一个继承于EaseBaseMessageCell的cell
先重写EaseBaseMessageCell的initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier model:(id)model方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier model:(id<IMessageModel>)model
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier model:model];
if (self) {
self.avatarSize = 35;//头像尺寸
self.messageNameIsHidden = YES;//是否显示发送者昵称
self.avatarCornerRadius = 3;//头像圆角大小
}
return self;
}
再重写setModel:(id)model方法
- (void)setModel:(id<IMessageModel>)model
{
[super setModel:model];
NSDictionary *dict = model.message.ext;
LCChatExtModel *extModel = [LCChatExtModel mj_objectWithKeyValues:dict];
if (extModel.type == 0]) {//名片
self.bubbleView.textLabel.hidden = YES;
self.cardView.hidden = NO;
self.cardView.extInfo = extModel;
[self _updateStatusWithWidth:195 withHeight:70];
}else{
self.cardView.hidden = YES;
self.bubbleView.textLabel.hidden = NO;
[self removeConstraint:_bubbleViewH];
[self removeConstraint:_bubbleViewW];
}
}
设置气泡,在这里说明一下,我最开始应该是直接修改气泡的frame没有成功,然后看环信是使用NSLayoutConstraint来UI适配,所以在这里我也使用了NSLayoutConstraint约束来调整气泡大小
/**
设置气泡
*/
- (void)_updateStatusWithWidth:(CGFloat)width withHeight:(CGFloat)height
{
[self removeConstraint:_bubbleViewH];
[self removeConstraint:_bubbleViewW];
_bubbleViewW = [NSLayoutConstraint constraintWithItem:self.bubbleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:width];
[self addConstraint:_bubbleViewW];
_bubbleViewH = [NSLayoutConstraint constraintWithItem:self.bubbleView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:height ];
[self addConstraint:_bubbleViewH];
[self layoutIfNeeded];
}
重写cellHeightWithModel方法,该方法是定义在tableView中获取Cell高度的方法
+ (CGFloat)cellHeightWithModel:(id<IMessageModel>)model
{
CGFloat surperHeight = [super cellHeightWithModel:model];
NSDictionary *dict = model.message.ext;
LCChatExtModel *extModel = [LCChatExtModel mj_objectWithKeyValues:dict];
if (extModel.type == 0) {
return surperHeight +55;
}
return surperHeight;
}
- 加载Cell
定义一个继承EaseMessageViewController的类,以后跳转到聊天页面使用该类,那么如何将cell放到TableView上呢?环信已经开发这个接口,下面在类中实现EaseMessageViewControllerDelegate的方法就可以了
遵守协议
self.delegate = self;//EaseMessageViewControllerDelegate
实现EaseMessageViewControllerDelegate方法
/**
设置自定义Cell
*/
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model{
if (model.bodyType == EMMessageBodyTypeText ) {
NSString *CellIdentifier = [LCChatXiaoYingCardCell cellIdentifierWithModel:model];
LCChatXiaoYingCardCell *cardCell = (LCChatXiaoYingCardCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cardCell == nil) {
cardCell = [[LCChatXiaoYingCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
cardCell.selectionStyle = UITableViewCellSelectionStyleNone;
cardCell.delegate = self;
}
cardCell.model = model;
return cardCell;
}
return nil;//如果不是自定义类型返回空
}
/**
设置聊天高度
*/
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
heightForMessageModel:(id<IMessageModel>)messageModel
withCellWidth:(CGFloat)cellWidth
{
LCChatExtModel *extModel = [LCChatExtModel mj_objectWithKeyValues:messageModel.message.ext];
if ([extModel.type == 0]) {
return [LCChatXiaoYingCardCell cellHeightWithModel:messageModel] ;
}
return 0;//如果不是自定义类型返回0
}
到这里呢,整个自定义就结束了