融云消息的自定义

前言:

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

 1:   自定义消息 Cell包括

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


融云消息的自定义_第1张图片

消息发送流程


融云消息的自定义_第2张图片

消息接收流程

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

     }

 }


融云消息的自定义_第3张图片

效果图

你可能感兴趣的:(融云消息的自定义)