如何创建自定义消息和展示的 cell?


            
2015-08-20 15:37 | iOS

回答:

自定义消息及展示可以分为一下几个步骤实现:

1、自定义消息类,自定义消息要继承 RCMessageContent 类,这个类里要提供把内容序列化和反序列化成 json 格式的方法。

2、注册自定义消息,需要将上步创建的消息类注册到 SDK 中。

3、新建自定义消息对应的展示的 cell ,这里可以根据布局来自定义显示内容。

4、注册自定义 cell 到页面的UICollectionView。

5、重写页面返回 cell 的方法

       -(RCMessageBaseCell *)rcConversationCollectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

6、重写页面返回 cell 高度的方法

      -(CGSize)rcConversationCollectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 

以下为示例代码,开发者可以参考实现:

1、新建自定义消息类 “SimpleMessage.h” 文件,代码如下:

#import <RongIMLib/RongIMLib.h>
#import <RongIMLib/RCMessageContentView.h>

#define RCLocalMessageTypeIdentifier @”RC:SimpleMsg”

/**
* 文本消息类定义
*/
@interface SimpleMessage : RCMessageContent <NSCoding,RCMessageContentView>
/** 文本消息内容 */
@property(nonatomic, strong) NSString* content;

/**
* 附加信息
*/
@property(nonatomic, strong) NSString* extra;

/**
* 根据参数创建文本消息对象
* @param content 文本消息内容
*/
+(instancetype)messageWithContent:(NSString *)content;

@end

 

`SimpleMessage.m` 文件代码如下:

#import “SimpleMessage.h”
#import <RongIMLib/RCUtilities.h>

@implementation SimpleMessage

+(instancetype)messageWithContent:(NSString *)content {
SimpleMessage *msg = [[SimpleMessage alloc] init];
if (msg) {
msg.content = content;
}

return msg;
}

+(RCMessagePersistent)persistentFlag {
return (MessagePersistent_ISPERSISTED | MessagePersistent_ISCOUNTED);
}

#pragma mark – NSCoding protocol methods
#define KEY_TXTMSG_CONTENT @”content”
#define KEY_TXTMSG_EXTRA @”extra”

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.content = [aDecoder decodeObjectForKey:KEY_TXTMSG_CONTENT];
self.extra = [aDecoder decodeObjectForKey:KEY_TXTMSG_EXTRA]; }
return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.content forKey:KEY_TXTMSG_CONTENT];
[aCoder encodeObject:self.extra forKey:KEY_TXTMSG_EXTRA];

}

#pragma mark – RCMessageCoding delegate methods

-(NSData *)encode {

NSMutableDictionary *dataDict=[NSMutableDictionary dictionary];
[dataDict setObject:self.content forKey:@"content"];
if (self.extra) {
[dataDict setObject:self.extra forKey:@"extra"];
}

if (self.senderUserInfo) {
NSMutableDictionary *__dic=[[NSMutableDictionary alloc]init];
if (self.senderUserInfo.name) {
[__dic setObject:self.senderUserInfo.name forKeyedSubscript:@"name"];
}
if (self.senderUserInfo.portraitUri) {
[__dic setObject:self.senderUserInfo.portraitUri forKeyedSubscript:@"icon"];
}
if (self.senderUserInfo.userId) {
[__dic setObject:self.senderUserInfo.userId forKeyedSubscript:@"id"];
}
[dataDict setObject:__dic forKey:@"user"];
}

//NSDictionary* dataDict = [NSDictionary dictionaryWithObjectsAndKeys:self.content, @"content", nil];
NSData *data = [NSJSONSerialization dataWithJSONObject:dataDict
options:kNilOptions
error:nil];
return data;
}

-(void)decodeWithData:(NSData *)data {
__autoreleasing NSError* __error = nil;
if (!data) {
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&__error];

if (json) {
self.content = json[@"content"];
self.extra = json[@"extra"];
NSObject *__object = [json objectForKey:@"user"];
NSDictionary *userinfoDic = nil;
if (__object &&[__object isMemberOfClass:[NSDictionary class]]) {
userinfoDic =__object;
}
if (userinfoDic) {
RCUserInfo *userinfo =[RCUserInfo new];
userinfo.userId = [userinfoDic objectForKey:@"id"];
userinfo.name =[userinfoDic objectForKey:@"name"];
userinfo.portaitUri =[userinfoDic objectForKey:@"icon"];
self.senderUserInfo = userinfo;
}

}
}
- (NSString *)conversationDigest
{
return @”会话列表要显示的内容”;
}
+(NSString *)getObjectName {
return @”xxxx”;
}
#if ! __has_feature(objc_arc)
-(void)dealloc
{
[super dealloc];
}
#endif//__has_feature(objc_arc)
@end

2、新建自定义消息展示 UI “SimpleMessageCell.h” 文件代码如下:

/**
* 文本消息Cell
*/
@interface SimpleMessageCell : RCMessageCell

/**
* 消息显示Label
*/
@property(strong, nonatomic) RCAttributedLabel *textLabel;

/**
* 消息背景
*/
@property(nonatomic, strong) UIImageView *bubbleBackgroundView;

/**
* 设置消息数据模型
*
* @param model 消息数据模型
*/
- (void)setDataModel:(RCMessageModel *)model;
@end

“SimpleMessageCell.m” 文件代码如下:

@interface SimpleMessageCell ()

- (void)initialize;

@end

@implementation SimpleMessageCell

- (NSDictionary *)attributeDictionary {
if (self.messageDirection == MessageDirection_SEND) {
return @{
@(NSTextCheckingTypeLink) : @{NSForegroundColorAttributeName : [UIColor blueColor]},
@(NSTextCheckingTypePhoneNumber) : @{NSForegroundColorAttributeName : [UIColor blueColor]}
};
} else {
return @{
@(NSTextCheckingTypeLink) : @{NSForegroundColorAttributeName : [UIColor blueColor]},
@(NSTextCheckingTypePhoneNumber) : @{NSForegroundColorAttributeName : [UIColor blueColor]}
};
}
return nil;
}

- (NSDictionary *)highlightedAttributeDictionary {
return [self attributeDictionary];
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initialize];
}
return self;
}
- (void)initialize {
self.bubbleBackgroundView = [[UIImageView alloc] initWithFrame:CGRectZero];
[self.messageContentView addSubview:self.bubbleBackgroundView];

self.textLabel = [[RCAttributedLabel alloc] initWithFrame:CGRectZero];
self.textLabel.attributeDictionary = [self attributeDictionary];
self.textLabel.highlightedAttributeDictionary = [self highlightedAttributeDictionary];
[self.textLabel setFont:[UIFont systemFontOfSize:Text_Message_Font_Size]];

self.textLabel.numberOfLines = 0;
[self.textLabel setLineBreakMode:NSLineBreakByWordWrapping];
[self.textLabel setTextAlignment:NSTextAlignmentLeft];
[self.textLabel setTextColor:[UIColor blackColor]];
//[self.textLabel setBackgroundColor:[UIColor yellowColor]];

[self.bubbleBackgroundView addSubview:self.textLabel];
self.bubbleBackgroundView.userInteractionEnabled = YES;
UILongPressGestureRecognizer *longPress =
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)];
[self.bubbleBackgroundView addGestureRecognizer:longPress];
}

- (void)setDataModel:(RCMessageModel *)model {
[super setDataModel:model];

[self setAutoLayout];
}
- (void)setAutoLayout {
RCTextMessage *_textMessage = (RCTextMessage *)self.model.content;
if (_textMessage) {
self.textLabel.text = _textMessage.content;
} else {
//DebugLog(@”[RongIMKit]: RCMessageModel.content is NOT RCTextMessage object”);
}
// ios 7
CGSize __textSize =
[_textMessage.content
boundingRectWithSize:CGSizeMake(self.baseContentView.bounds.size.width -
(10 + [RCIM sharedKit].globalMessagePortraitSize.width + 10) * 2 – 5 -
35,
MAXFLOAT)
options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:@{
NSFontAttributeName : [UIFont systemFontOfSize:Text_Message_Font_Size]
} context:nil]
.size;
__textSize = CGSizeMake(ceilf(__textSize.width), ceilf(__textSize.height));
CGSize __labelSize = CGSizeMake(__textSize.width + 5, __textSize.height + 5);

CGFloat __bubbleWidth = __labelSize.width + 15 + 20 < 50 ? 50 : (__labelSize.width + 15 + 20);
CGFloat __bubbleHeight = __labelSize.height + 5 + 5 < 35 ? 35 : (__labelSize.height + 5 + 5);

CGSize __bubbleSize = CGSizeMake(__bubbleWidth, __bubbleHeight);

CGRect messageContentViewRect = self.messageContentView.frame;

if (MessageDirection_RECEIVE == self.messageDirection) {
messageContentViewRect.size.width = __bubbleSize.width;
self.messageContentView.frame = messageContentViewRect;

self.bubbleBackgroundView.frame = CGRectMake(0, 0, __bubbleSize.width, __bubbleSize.height);

self.textLabel.frame = CGRectMake(20, 5, __labelSize.width, __labelSize.height);
self.bubbleBackgroundView.image = [self imageNamed:@"chat_from_bg_normal" ofBundle:@"RongCloud.bundle"];
UIImage *image = self.bubbleBackgroundView.image;
self.bubbleBackgroundView.image = [self.bubbleBackgroundView.image
resizableImageWithCapInsets:UIEdgeInsetsMake(image.size.height * 0.8, image.size.width * 0.8,
image.size.height * 0.2, image.size.width * 0.2)];
} else {
messageContentViewRect.size.width = __bubbleSize.width;
messageContentViewRect.origin.x =
self.baseContentView.bounds.size.width -
(messageContentViewRect.size.width + 10 + [RCIM sharedKit].globalMessagePortraitSize.width + 10);
self.messageContentView.frame = messageContentViewRect;

self.bubbleBackgroundView.frame = CGRectMake(0, 0, __bubbleSize.width, __bubbleSize.height);

self.textLabel.frame = CGRectMake(15, 5, __labelSize.width, __labelSize.height);

self.bubbleBackgroundView.image = [self imageNamed:@"chat_to_bg_normal" ofBundle:@"RongCloud.bundle"];
UIImage *image = self.bubbleBackgroundView.image;
self.bubbleBackgroundView.image = [self.bubbleBackgroundView.image
resizableImageWithCapInsets:UIEdgeInsetsMake(image.size.height * 0.8, image.size.width * 0.2,
image.size.height * 0.2, image.size.width * 0.8)];
}

}
- (UIImage *)imageNamed:(NSString *)name ofBundle:(NSString *)bundleName {
UIImage *image = nil;
NSString *image_name = [NSString stringWithFormat:@"%@.png", name];
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *bundlePath = [resourcePath stringByAppendingPathComponent:bundleName];
NSString *image_path = [bundlePath stringByAppendingPathComponent:image_name];
image = [[UIImage alloc] initWithContentsOfFile:image_path];

return image;
}

- (void)longPressed:(id)sender {
UILongPressGestureRecognizer *press = (UILongPressGestureRecognizer *)sender;
if (press.state == UIGestureRecognizerStateEnded) {
//DebugLog(@”long press end”);
return;
} else if (press.state == UIGestureRecognizerStateBegan) {
[self.delegate didLongTouchMessageCell:self.model inView:self.bubbleBackgroundView];
}
}

@end

3、注册自定义消息类及 UI

SDK 初始化方法 initWithAppKey 之后后注册消息类型
[[RCIMClient sharedClient]registerMessageType:SimpleMessage.class];

会话页面注册 UI
[self registerClass:[SimpleMessageCell class] forCellWithReuseIdentifier:@"SimpleMessageCell"];

4、重写会话页面自定义消息展示的两个方法

-(RCMessageBaseCell *)rcConversationCollectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
RCMessageModel *model = self.conversationDataRepository[indexPath.row];
NSString * cellIndentifier=@”SimpleMessageCell”;
RCMessageBaseCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIndentifier           forIndexPath:indexPath];
[cell setDataModel:model];
return cell;
}
-(CGSize)rcConversationCollectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
//返回自定义cell的实际高度(这里请返回消息的实际大小)
return CGSizeMake(300, 60);
}

至此已完成自定义消息类型及展示,谢谢!

注意:两个协议代理方法,在对应自定义消息发送的时候,才会被调用。



您认为此回答对您有帮助?

共有 22 位开发者认为此问题有帮助

我对此仍有疑问!继续追问