融云消息的自定义

前言:

上一次分享了融云的集成和使用,基本上满足了大众需求和微脉项目中的要求。但是小编私下没有偷懒,一直在探索更多的内容。融云简单的文字cell或则单个图片cell展示,已经满足不了我们日益强大的需求。所以这里以医生名片的自定义为例子实现一个自定义cell。

 1:   自定义消息 Cell包括

 1.1:在此之前我们先了解一下融云消息的发送机制和接收机制。(看图说话)


消息发送流程


消息接收流程

1.2  自定义消息 Cell 显示需要完成两步走:

1. 自定义消息并注册消息类型

2. 自定义消息 Cell 并注册 Cell

1.2.1. 自定义消息并注册消息类型

您需要继承 RCMessageContent 实现自定义消息类,并在 SDK 初始化之后,注册自定义消息。

RCMessageContent 是消息内容类,是所有消息的基类。您可以继承此类,并实现其中的协议,来实现自定义消息。

RCMessageContent 主要有三个协议:

1. 编解码协议 RCMessageCoding

2. 存储协议 RCMessagePersistentCompatible

3. 内容摘要协议 RCMessageContentView(可选)

其中,RCMessageCoding 主要有三个功能:提供消息唯一标识符、消息发送时将消息中的所有信息编码为 json 数据传输、消息接收时将 json 数据解码还原为消息对象。

RCMessagePersistentCompatible 用于确定消息内容的存储策略,指明此消息类型在本地是否存储、是否计入未读消息数。

RCMessageContentView 用于在会话列表和本地通知中显示消息的摘要。

最后在初始化融云的时候完成注册。

[[RCIM sharedRCIM] registerMessageType:[WMRCRecommendDoctorMessage class]];

1.2.2. 自定义消息 Cell 注册并显示

如果消息不需要显示头像,请继承 RCMessageBaseCell。如果需要显示,请继承 RCMessageCell。

请在初始化方法中实现 Cell 的布局,并重写下面方法来返回 Cell 的 Size:

+ (CGSize)sizeForMessageModel:(RCMessageModel *)model

       withCollectionViewWidth:(CGFloat)collectionViewWidth

          referenceExtraHeight:(CGFloat)extraHeight;

然后在聊天试图页面用一下方法进行cell的注册,以及与消息的绑定。

[self registerClass:[WMRCRecommendDoctorCell class]

        forMessageClass:[WMRCRecommendDoctorMessage class]];

2:原理的方面都已经说完了,下面直接粗暴的上代码吧。

2.1 自定义消息体WMRCRecommendDoctorMessage(医生名片)

申明一个标志:这个标志是我们发送,接收,以及和安卓 H5互发消息时候的依据。

''#define    WMRCRecommendDoctorMessageTypeIdentifier @"RCD:WMRecommendDoctorMsg"

根据需求 申明需要传输的字段

/*!  医生头像 字符串信息  */

@property(nonatomic, strong) NSString *doctorHeader;

/*! 医生名字 */

 @property(nonatomic, strong) NSString *doctorName;

 /*! 医生科室 */

@property(nonatomic, strong) NSString *doctorSection;

 /*!  预留附加信息 */

@property(nonatomic, strong) NSString *extra;

申明消息的初始话方法

/*!  初始化测试消息

@param content 文本内容

  @return        测试消息对象 */

 + (instancetype)messageWithInquiryTextMsg:(NSString *)inquiryTextMsg withInquiryPicture:(NSMutableArray *)inquiryPictureArr;

在.m中实现以下方法

///初始化

 + (instancetype)messageWithDoctorHeader:(NSString *)doctorHeader withDoctorName:(NSString *)doctorName withDoctorSection:(NSString *)doctorSection{

    WMRCRecommendDoctorMessage *text = [[WMRCRecommendDoctorMessage alloc] init];

     if (text) {

       text.doctorHeader = doctorHeader;

        text.doctorName=doctorName;

       text.doctorSection=doctorSection;

   }

     return text;

}

消息是否存储,是否计入未读数

 + (RCMessagePersistent)persistentFlag {

    return (MessagePersistent_ISPERSISTED | MessagePersistent_ISCOUNTED);

}

NSCoding(反序列化)

 - (instancetype)initWithCoder:(NSCoder *)aDecoder {

    self = [super init];

     if (self) {

         self.doctorHeader = [aDecoder decodeObjectForKey:@"doctorHeader"];

         self.extra = [aDecoder decodeObjectForKey:@"extra"];

         self.doctorName = [aDecoder decodeObjectForKey:@"doctorName"];

         self.doctorSection = [aDecoder decodeObjectForKey:@"doctorSection"];


     }

     return self;

 }

NSCoding 序列化

 - (void)encodeWithCoder:(NSCoder *)aCoder {

     [aCoder encodeObject:self.doctorSection forKey:@"doctorSection"];

     [aCoder encodeObject:self.extra forKey:@"extra"];

    [aCoder encodeObject:self.doctorName forKey:@"doctorName"];

     [aCoder encodeObject:self.doctorHeader forKey:@"doctorHeader"];

}

将消息内容编码成json

 - (NSData *)encode {

     NSMutableDictionary *dataDict = [NSMutableDictionary dictionary];

     [dataDict setObject:self.doctorHeader forKey:@"doctorHeader"];

     [dataDict setObject:self.doctorSection forKey:@"doctorSection"];

     [dataDict setObject:self.doctorName forKey:@"doctorName"];

     if (self.extra) {

         [dataDict setObject:self.extra forKey:@"extra"];

     }

     if (self.senderUserInfo) {

         NSMutableDictionary *userInfoDic = [[NSMutableDictionary alloc] init];

         if (self.senderUserInfo.name) {

             [userInfoDic setObject:self.senderUserInfo.name

                  forKeyedSubscript:@"name"];

         }

         if (self.senderUserInfo.portraitUri) {

             [userInfoDic setObject:self.senderUserInfo.portraitUri

                  forKeyedSubscript:@"icon"];

         }

         if (self.senderUserInfo.userId) {

             [userInfoDic setObject:self.senderUserInfo.userId

                  forKeyedSubscript:@"id"];

         }

         [dataDict setObject:userInfoDic forKey:@"user"];

     }

     NSData *data = [NSJSONSerialization dataWithJSONObject:dataDict

                                                    options:kNilOptions

                                                      error:nil];

     return data;

 }

将json解码生成消息内容

 - (void)decodeWithData:(NSData *)data {

     if (data) {

         __autoreleasing NSError *error = nil;

        NSDictionary *dictionary =

         [NSJSONSerialization JSONObjectWithData:data

                                         options:kNilOptions

                                           error:&error];

         if (dictionary) {

             self.doctorName = dictionary[@"doctorName"];

             self.extra = dictionary[@"extra"];

             self.doctorSection = dictionary[@"doctorSection"];

             self.doctorHeader = dictionary[@"doctorHeader"];

             NSDictionary *userinfoDic = dictionary[@"user"];

             [self decodeUserInfo:userinfoDic];

         }

     }

 }


会话列表中显示的摘要

 - (NSString *)conversationDigest {

     return self.doctorName;

 }

消息的类型名

 + (NSString *)getObjectName {

     return WMRCRecommendDoctorMessageTypeIdentifier;

 }

 2.2 自定义消息体WMRCInquiryMessageCell

根据需求申明变量

/*! 医生头像 */

 @property(strong, nonatomic) UIImageView *headerImageView;

 /*! 医生姓名 */

 @property(strong, nonatomic) UILabel *nameLable;

 /*! 医生科室 */

 @property(strong, nonatomic)UILabel *sectionLable;

 /*! 背景View */

 @property(nonatomic, strong) UIImageView *bubbleBackgroundView;

在.m中声明一些全局变量 方便日后容易改动

#define kheight 90    //名片的高度

 #define kwidth  220  //名片的宽度

 #define kSpacing 7    //个控件之间的间隔

 #define kBubbleSharp 10 //气泡尖尖的宽度

 #define kheaderHeight 60 //头像的宽高

当应用自定义消息时,必须实现该方法来返回cell的Size。

其中,extraHeight是Cell根据界面上下文,需要额外显示的高度(比如时间、用户名的高度等)。

一般而言,Cell的高度应该是内容显示的高度再加上extraHeight的高度。

+ (CGSize)sizeForMessageModel:(RCMessageModel *)model

   withCollectionViewWidth:(CGFloat)collectionViewWidth

 referenceExtraHeight:(CGFloat)extraHeight {

//由于名片的高度,宽度一定 所以 下面这句代码是没有用途的

 WMRCRecommendDoctorMessage *message = (WMRCRecommendDoctorMessage *)model.content;

    //由于名片的高度,宽度一定 所以可以直接返回固定高度 50 是从文档那看到的之和10+20+10+10

 return CGSizeMake(kScreen_width, kheight+55);

 }

cell 的初始化方法

- (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;

 }

创建cell显示的控件

- (void)initialize {

    self.bubbleBackgroundView = [[UIImageView alloc] initWithFrame:CGRectZero];

     //[self.messageContentView 是底层的View

     [self.messageContentView addSubview:self.bubbleBackgroundView];

     self.messageContentView.backgroundColor=[UIColor greenColor];

    //头像

    self.headerImageView=[[UIImageView alloc]init];

     [self.bubbleBackgroundView addSubview:self.headerImageView];

    //名字

     self.nameLable=[[RCAttributedLabel alloc] initWithFrame:CGRectZero];

     [self.nameLable setFont:[UIFont systemFontOfSize:Test_Message_Font_Size]];

     self.nameLable.numberOfLines = 0;

     [self.nameLable setLineBreakMode:NSLineBreakByWordWrapping];

     [self.nameLable setTextAlignment:NSTextAlignmentLeft];

     [self.nameLable setTextColor:[UIColor blackColor]];

     [self.bubbleBackgroundView addSubview:self.nameLable];

     //科室

     self.sectionLable = [[RCAttributedLabel alloc] initWithFrame:CGRectZero];

     [self.sectionLable setFont:[UIFont systemFontOfSize:Test_Message_Font_Size]];

     self.sectionLable.numberOfLines = 0;

     [self.sectionLable setLineBreakMode:NSLineBreakByWordWrapping];

     [self.sectionLable setTextAlignment:NSTextAlignmentLeft];

     [self.sectionLable setTextColor:[UIColor blackColor]];

     [self.bubbleBackgroundView addSubview:self.sectionLable];

     self.bubbleBackgroundView.userInteractionEnabled = YES;

     UILongPressGestureRecognizer *longPress =

     [[UILongPressGestureRecognizer alloc]

      initWithTarget:self

      action:@selector(longPressed:)];

     [self.bubbleBackgroundView addGestureRecognizer:longPress];

     UITapGestureRecognizer *textMessageTap = [[UITapGestureRecognizer alloc]

                                               initWithTarget:self

                                               action:@selector(tapTextMessage:)];     textMessageTap.numberOfTapsRequired = 1;

     textMessageTap.numberOfTouchesRequired = 1;

     //[self.textLabel addGestureRecognizer:textMessageTap];

     //self.textLabel.userInteractionEnabled = YES;

 }

set方法获取数据

- (void)setDataModel:(RCMessageModel *)model {

 [super setDataModel:model];

 [self setAutoLayout];

}

根据model对控件在cell上布局,其中分为接收方和发送方

 -(void)setAutoLayout {

 //创建控件

 WMRCRecommendDoctorMessage *testMessage = (WMRCRecommendDoctorMessage *)self.model.content;

 if (testMessage) {

 self.nameLable.text = testMessage.doctorName;

 [self.headerImageView sd_setImageWithURL:[NSURL URLWithString:testMessage.doctorHeader]];

 self.sectionLable.text=testMessage.doctorSection;

 }

 //获取文字消息的size

 //CGSize textLabelSize = [[self class] getTextLabelSize:testMessage];

 //大背景的size(单纯的按照 textLabelSize 是不对的)

 CGSize bubbleBackgroundViewSize =CGSizeMake(kwidth, kheight);

 //消息内容的View

 CGRect messageContentViewRect = self.messageContentView.frame;


 //拉伸图片

 if (MessageDirection_RECEIVE == self.messageDirection) {//接受

 self.headerImageView.frame=CGRectMake(2*kSpacing, kSpacing, kheaderHeight, kheaderHeight);

 //文字的位置

 self.nameLable.frame =

CGRectMake(14+kheaderHeight+kSpacing, kSpacing, kwidth-kheaderHeight-kSpacing-kBubbleSharp, kBubbleSharp*2);

 //图片的位置 self.sectionLable.frame=CGRectMake(self.nameLable.frame.origin.x, self.nameLable.frame.origin.y+self.nameLable.frame.size.height,kwidth-kheaderHeight-kSpacing-kBubbleSharp, kheight-40);

 //消息内容的View的宽 赋值

 messageContentViewRect.size.width = bubbleBackgroundViewSize.width;

 messageContentViewRect.size.height = bubbleBackgroundViewSize.height;

 //大泡泡背景 赋值

 self.messageContentView.frame = messageContentViewRect;

self.bubbleBackgroundView.frame = CGRectMake(

 0, 0, bubbleBackgroundViewSize.width, bubbleBackgroundViewSize.height);

 UIImage *image = [RCKitUtility imageNamed:@"chat_from_bg_normal"

 ofBundle:@"RongCloud.bundle"];

self.bubbleBackgroundView.image = [image

    resizableImageWithCapInsets:UIEdgeInsetsMake(image.size.height * 0.8,

image.size.width * 0.8,

image.size.height * 0.2,

image.size.width * 0.2)];

 } else {

 self.headerImageView.frame=CGRectMake(kSpacing, kSpacing, kheaderHeight, kheaderHeight);

 //自己发消息

 self.nameLable.frame =

 CGRectMake(kSpacing+kheaderHeight+kSpacing, kSpacing, kwidth-kheaderHeight-2*kSpacing-2*kBubbleSharp, 2*kBubbleSharp);

 //图片的位置

self.sectionLable.frame=CGRectMake(self.nameLable.frame.origin.x, self.nameLable.frame.origin.y+self.nameLable.frame.size.height, kwidth-kheaderHeight-14-2*kBubbleSharp, kheight-40);

 //消息内容的View的宽 赋值

 messageContentViewRect.size.width = bubbleBackgroundViewSize.width;

 messageContentViewRect.size.height = bubbleBackgroundViewSize.height;

 messageContentViewRect.origin.x =

 self.baseContentView.bounds.size.width -

 (messageContentViewRect.size.width + HeadAndContentSpacing +

 [RCIM sharedRCIM].globalMessagePortraitSize.width + kBubbleSharp);

 self.messageContentView.frame = messageContentViewRect;

 self.bubbleBackgroundView.frame = CGRectMake(

0, 0, bubbleBackgroundViewSize.width, bubbleBackgroundViewSize.height);

 UIImage *image = [RCKitUtility imageNamed:@"chat_to_bg_normal"

ofBundle:@"RongCloud.bundle"];

 self.bubbleBackgroundView.image = [image

resizableImageWithCapInsets:UIEdgeInsetsMake(image.size.height * 0.8,

image.size.width * 0.2,

image.size.height * 0.2,

image.size.width * 0.8)];

 }

 }

点击问题部分的手势,利用这个在视图页面进行交互

- (void)tapTextMessage:(UIGestureRecognizer *)gestureRecognizer {

     if ([self.delegate respondsToSelector:@selector(didTapMessageCell:)]) {

         [self.delegate didTapMessageCell:self.model];

     }

 }

长按手势,利用这个在视图页面进行交互

- (void)longPressed:(id)sender {

     UILongPressGestureRecognizer *press = (UILongPressGestureRecognizer *)sender;

     if (press.state == UIGestureRecognizerStateEnded) {

         return;

     } else if (press.state == UIGestureRecognizerStateBegan) {

         [self.delegate didLongTouchMessageCell:self.model

                                         inView:self.bubbleBackgroundView];

     }

 }


效果图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容