在集成环信即时通讯的基础上,要做好友推荐的功能,查了下SDK发现里面提供了自定义消息的接口,接下来我们就可以根据自己的需要去自定义消息视图了
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)messageModel{
环信的注释是: 获取消息自定义cell
用户根据messageModel判断是否显示自定义cell,返回nil显示默认cell,否则显示用户自定义cell
既然提供了方法,那么接下来我们就可以根据自己的需求去操作了(这里只做好友推荐的视图)
首先创建了继承EaseBaseMessageCell的自定义消息视图(有些博友问我后面不执行代理方法,在这里特此说明下,我是继承重写的,好多方法都是自己添加的,请留意你们的项目是直接修改还是继承)
.h
@interface IMChatBusinessCardCell : EaseBaseMessageCell
@end
.m
#import "IMChatBusinessCardCell.h"
#import "EaseBubbleView+IMChatBusinessCard.h"
static const CGFloat kCellHeight = 110.0f;
@implementation IMChatBusinessCardCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier model:(id)model{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier model:model];
if (self) {
self.hasRead.hidden = YES;
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
return self;
}
- (BOOL)isCustomBubbleView:(id)model{
return YES;
}
- (void)setCustomModel:(id)model{
UIImage *image = model.image;
if (!image) {
[self.bubbleView.imageView sd_setImageWithURL:[NSURL URLWithString:model.fileURLPath] placeholderImage:[UIImage imageNamed:model.failImageName]];
} else {
_bubbleView.imageView.image = image;
}
if (model.avatarURLPath) {
[self.avatarView sd_setImageWithURL:[NSURL URLWithString:model.avatarURLPath] placeholderImage:model.avatarImage];
} else {
self.avatarView.image = model.avatarImage;
}
}
- (void)setCustomBubbleView:(id)model{
[_bubbleView setupBusinessCardBubbleView];
_bubbleView.imageView.image = [UIImage imageNamed:@"shouyeliaotiankuangbai"];
}
- (void)updateCustomBubbleViewMargin:(UIEdgeInsets)bubbleMargin model:(id)mode{
[_bubbleView updateBusinessCardMargin:bubbleMargin];
_bubbleView.translatesAutoresizingMaskIntoConstraints = YES;
CGFloat bubbleViewHeight = 84;// 气泡背景图高度
CGFloat nameLabelHeight = 15;// 昵称label的高度
if (mode.isSender) {
_bubbleView.frame =
CGRectMake([UIScreen mainScreen].bounds.size.width - 273.5, nameLabelHeight, 213, bubbleViewHeight);
}else{
_bubbleView.frame = CGRectMake(55, nameLabelHeight, 213, bubbleViewHeight);
}
// 这里强制调用内部私有方法
[_bubbleView _setupConstraintsXX];
}
- (NSString *)cellIdentifierWithModel:(id)model{
return NSStringFromClass([self class]);
}
- (CGFloat)cellHeightWithModel:(id)model{
return kCellHeight;
}
- (void)setModel:(id)model{
[super setModel:model];
NSDictionary *dict = model.message.ext;
self.bubbleView.userNameLabel.text = dict[@"cardUserName"];
self.bubbleView.userPhoneLabel.text = dict[@"cardUserPhone"];
_hasRead.hidden = YES;//名片消息不显示已读
}
- (void)layoutSubviews
{
[super layoutSubviews];
NSString *imageName = self.model.isSender ? @"RedpacketCellResource.bundle/redpacket_sender_bg" : @"RedpacketCellResource.bundle/redpacket_receiver_bg";
UIImage *image = self.model.isSender ? [[UIImage imageNamed:imageName] stretchableImageWithLeftCapWidth:30 topCapHeight:35] :
[[UIImage imageNamed:imageName] stretchableImageWithLeftCapWidth:20 topCapHeight:35];
// 等待接入名片的背景图片
// self.bubbleView.backgroundImageView.image = image;
}
在这里我们需要将控件的属性接口放出来,在这里有两种方式,一种是直接在EaseBubbleView里自行添加,还有一种是创建它的Category.这里采用第二种方式
.h
#import "EaseBubbleView.h"
@interface EaseBubbleView (IMChatBusinessCard)
// 用户头像
@property (strong, nonatomic) UIImageView *userHeaderImageView;
// 用户昵称
@property (strong, nonatomic) UILabel *userNameLabel;
// 用户手机号
@property (strong, nonatomic) UILabel *userPhoneLabel;
// 分割线
@property (strong, nonatomic) UIView *line;
// tip标签
@property (strong, nonatomic) UILabel *tipsLabel;
// 设置名片气泡
- (void)setupBusinessCardBubbleView;
// 更新名片间距
- (void)updateBusinessCardMargin:(UIEdgeInsets)margin;
// 设置约束
- (void)_setupConstraintsXX;
@end
.m
#import "EaseBubbleView+IMChatBusinessCard.h"
#import
static char _userHeaderImageView_;
static char _userNameLabel_;
static char _userPhoneLabel_;
static char _line_;
static char _tipsLabel_;
@implementation EaseBubbleView (IMChatBusinessCard)
- (void)_setupConstraintsXX{
[self.marginConstraints removeAllObjects];
//userHeaderImageView
NSLayoutConstraint *userHeaderImageViewTopConstraint =
[NSLayoutConstraint constraintWithItem:self.userHeaderImageView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:10];
NSLayoutConstraint *userHeaderImageViewLeadingConstraint =
[NSLayoutConstraint constraintWithItem:self.userHeaderImageView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10];
[self.marginConstraints addObject:userHeaderImageViewTopConstraint];
[self.marginConstraints addObject:userHeaderImageViewLeadingConstraint];
NSLayoutConstraint *userHeaderImageViewHeightConstraint =
[NSLayoutConstraint constraintWithItem:self.userHeaderImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:36];
NSLayoutConstraint *userHeaderImageViewWidthConstraint =
[NSLayoutConstraint constraintWithItem:self.userHeaderImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:36];
[self.userHeaderImageView addConstraint:userHeaderImageViewHeightConstraint];
[self.userHeaderImageView addConstraint:userHeaderImageViewWidthConstraint];
// userNameLabel
NSLayoutConstraint *userNameLabelWithMarginTopConstraint =
[NSLayoutConstraint constraintWithItem:self.userNameLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.userHeaderImageView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:2];
NSLayoutConstraint *userNameLabelWithMarginRightConstraint =
[NSLayoutConstraint constraintWithItem:self.userNameLabel
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-self.margin.right];
NSLayoutConstraint *userNameLabelWithMarginLeftConstraint =
[NSLayoutConstraint constraintWithItem:self.userNameLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.userHeaderImageView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:10];
[self.marginConstraints addObject:userNameLabelWithMarginRightConstraint];
[self.marginConstraints addObject:userNameLabelWithMarginTopConstraint];
[self.marginConstraints addObject:userNameLabelWithMarginLeftConstraint];
// userPhoneLabel
NSLayoutConstraint *userPhoneLabelTopConstraint =
[NSLayoutConstraint constraintWithItem:self.userPhoneLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.userHeaderImageView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:1];
NSLayoutConstraint *userPhoneLabelLeftConstraint =
[NSLayoutConstraint constraintWithItem:self.userPhoneLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.userNameLabel
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
NSLayoutConstraint *userPhoneLabelRightConstraint =
[NSLayoutConstraint constraintWithItem:self.userPhoneLabel
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-self.margin.right];
[self.marginConstraints addObject:userPhoneLabelTopConstraint];
[self.marginConstraints addObject:userPhoneLabelLeftConstraint];
[self.marginConstraints addObject:userPhoneLabelRightConstraint];
// line
NSLayoutConstraint *lineTopConstraint =
[NSLayoutConstraint constraintWithItem:self.line
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.userHeaderImageView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:10];
NSLayoutConstraint *lineLeftConstraint =
[NSLayoutConstraint constraintWithItem:self.line
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.userHeaderImageView
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
NSLayoutConstraint *lineRightConstraint =
[NSLayoutConstraint constraintWithItem:self.line
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-self.margin.right];
NSLayoutConstraint *lineHeightConstraint =
[NSLayoutConstraint constraintWithItem:self.line
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:1];
[self.marginConstraints addObject:lineTopConstraint];
[self.marginConstraints addObject:lineLeftConstraint];
[self.marginConstraints addObject:lineRightConstraint];
[self.marginConstraints addObject:lineHeightConstraint];
// tipsLabel
NSLayoutConstraint *tipsLabelTopConstraint =
[NSLayoutConstraint constraintWithItem:self.tipsLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.line
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:4];
NSLayoutConstraint *tipsLabelLeftConstraint =
[NSLayoutConstraint constraintWithItem:self.tipsLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.line
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
NSLayoutConstraint *tipsLabelRightConstraint =
[NSLayoutConstraint constraintWithItem:self.tipsLabel
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.line
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0];
[self.marginConstraints addObject:tipsLabelTopConstraint];
[self.marginConstraints addObject:tipsLabelLeftConstraint];
[self.marginConstraints addObject:tipsLabelRightConstraint];
[self addConstraints:self.marginConstraints];
NSLayoutConstraint *backImageConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0f constant:260];
[self.superview addConstraint:backImageConstraint];
}
#pragma mark - public
- (void)setupBusinessCardBubbleView{
// 头像
self.userHeaderImageView = [UIImageView new];
[self.userHeaderImageView setImage:[UIImage imageNamed:STR_DEFAULT_APPIMAGE]];
self.userHeaderImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundImageView addSubview:self.userHeaderImageView];
// 昵称
self.userNameLabel = [UILabel new];
self.userNameLabel.font = [UIFont systemFontOfSize:15.0f];
self.userNameLabel.textColor = [UIColor lightGrayColor];
self.userNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundImageView addSubview:self.userNameLabel];
// 手机号
self.userPhoneLabel = [UILabel new];
self.userPhoneLabel.font = [UIFont systemFontOfSize:13.0f];
self.userPhoneLabel.textColor = [UIColor lightGrayColor];
self.userPhoneLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundImageView addSubview:self.userPhoneLabel];
// 分隔线
self.line = [UIView new];
self.line.backgroundColor = [UIColor blackColor];
self.line.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundImageView addSubview:self.line];
// 提示字 个人名片
self.tipsLabel = [UILabel new];
self.tipsLabel.text = @"个人名片";
self.tipsLabel.font = [UIFont systemFontOfSize:12.0f];
self.tipsLabel.textColor = [UIColor lightGrayColor];
self.tipsLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.backgroundImageView addSubview:self.tipsLabel];
[self _setupConstraintsXX];
}
- (void)updateBusinessCardMargin:(UIEdgeInsets)margin
{
if (_margin.top == margin.top && _margin.bottom == margin.bottom && _margin.left == margin.left && _margin.right == margin.right) {
return;
}
_margin = margin;
[self removeConstraints:self.marginConstraints];
[self _setupConstraintsXX];
}
#pragma mark - getter and setter
- (void)setUserHeaderImageView:(UIImageView *)userHeaderImageView
{
objc_setAssociatedObject(self, &_userHeaderImageView_, userHeaderImageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIImageView *)userHeaderImageView
{
return objc_getAssociatedObject(self, &_userHeaderImageView_);
}
- (void)setUserNameLabel:(UILabel *)userNameLabel
{
objc_setAssociatedObject(self, &_userNameLabel_, userNameLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UILabel *)userNameLabel
{
return objc_getAssociatedObject(self, &_userNameLabel_);
}
- (void)setUserPhoneLabel:(UILabel *)userPhoneLabel
{
objc_setAssociatedObject(self, &_userPhoneLabel_, userPhoneLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UILabel *)userPhoneLabel
{
return objc_getAssociatedObject(self, &_userPhoneLabel_);
}
- (void)setLine:(UIView *)line
{
objc_setAssociatedObject(self, &_line_, line, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView *)line
{
return objc_getAssociatedObject(self, &_line_);
}
- (void)setTipsLabel:(UILabel *)tipsLabel
{
objc_setAssociatedObject(self, &_tipsLabel_, tipsLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UILabel *)tipsLabel
{
return objc_getAssociatedObject(self, &_tipsLabel_);
}
@end
现在都定义好了,再回到自定义消息样式的方法中添加判断就好了
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id)messageModel{
if (messageModel.bodyType == EMMessageBodyTypeText &&
[[messageModel text] hasPrefix:@"[名片]"]) {
NSString *CellIdentifier = [IMChatBusinessCardCell cellIdentifierWithModel:messageModel];
IMChatBusinessCardCell *cell = (IMChatBusinessCardCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[IMChatBusinessCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:messageModel];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.model = messageModel;
return cell;
}
return nil;
}
说到这里,那么当我们推荐事件触发的时候要怎么做呢,这里我随便给了些假数据,仅供参考
- (void)sendRecommendFriend{
RMLog(@"发送推荐好友");
EMMessage *message = [EaseSDKHelper sendTextMessage:@"[名片]"
to:@"600018"
messageType:EMChatTypeChat
messageExt:@{@"cardUserName":@"Raymon",@"cardUserPhone":@"13843838438"}];
[[EMClient sharedClient].chatManager sendMessage:message progress:^(int progress) {
RMLog(@"%d",progress);
} completion:^(EMMessage *message, EMError *error) {
TXHChatViewController *chatController = [[TXHChatViewController alloc] initWithConversationChatter:@"600018" conversationType:EMConversationTypeChat];
[self.navigationController pushViewController:chatController animated:YES];
}];
}
到这里,我们发送名片的功能已经做完,但可能也会有人和我一样,如果要点击名片,要怎么去做呢,这里我问了下技术咨询,是让我在EaseMessageCell的bubbleViewTapAction方法中只保留
if ([_delegate respondsToSelector:@selector(messageCellSelected:)]) {
[_delegate messageCellSelected:_model];
return;
}
这一句,开始我也感觉其余的判断是多余的,这样就完全可以了,但是后面发现如果这样修改后,到了后面自己要写的和判断的就要好多,所以变化了下思路,在EaseMessageViewController中添加了个点击自定义视图(名片)消息的协议,在- (void)messageCellSelected:(id
的
switch
判断中协议
case EMMessageBodyTypeText:
{
if ([_delegate respondsToSelector:@selector(didSelectMessageModel:)]) {
[_delegate didSelectMessageModel:model];
}
}
然后在回到自己的控制器中进行判断,个人感觉这样可能更方便些吧
- (void)didSelectMessageModel:(id<IMessageModel>)messageModel{
if (messageModel.bodyType == EMMessageBodyTypeText &&
[[messageModel text] hasPrefix:@"[名片]"]){
// 点击名片
RMLog(@"点击名片");
}
}
好友推荐暂时就到这里,后续还有好多功能,这里只是积累下自己的开发心得和体会,也给自己留个记录备注.而这些主要是参考了环信Demo里的红包功能去仿写的,当然开始也在网上查询了好多,都没有发现完整的.希望在这里一起学习
前往下载: http://download.csdn.net/download/sinat_28585351/9801988
特此声明,有些博友下载链接后说没有Demo,我提供的只是逻辑,发送红包和其他自定义视图都可适用,而链接下载的只是自定义的名片类,本身就不是完整的Demo,自行选择下载,可以把下载后的类文件直接拷贝道项目中使用,不会用就乱喷的请绕行