融云消息的自定義

前言:

上一次分享了融云的集成和使用,基本上滿足了大眾需求和微脈項(xiàng)目中的要求。但是小編私下沒(méi)有偷懶,一直在探索更多的內(nèi)容。融云簡(jiǎn)單的文字cell或則單個(gè)圖片cell展示,已經(jīng)滿足不了我們?nèi)找鎻?qiáng)大的需求。所以這里以醫(yī)生名片的自定義為例子實(shí)現(xiàn)一個(gè)自定義cell。

?1: ? 自定義消息 Cell包括

?1.1:在此之前我們先了解一下融云消息的發(fā)送機(jī)制和接收機(jī)制。(看圖說(shuō)話)


消息發(fā)送流程


消息接收流程

1.2? 自定義消息 Cell 顯示需要完成兩步走:

1. 自定義消息并注冊(cè)消息類型

2. 自定義消息 Cell 并注冊(cè) Cell

1.2.1. 自定義消息并注冊(cè)消息類型

您需要繼承 RCMessageContent 實(shí)現(xiàn)自定義消息類,并在 SDK 初始化之后,注冊(cè)自定義消息。

RCMessageContent 是消息內(nèi)容類,是所有消息的基類。您可以繼承此類,并實(shí)現(xiàn)其中的協(xié)議,來(lái)實(shí)現(xiàn)自定義消息。

RCMessageContent 主要有三個(gè)協(xié)議:

1. 編解碼協(xié)議 RCMessageCoding

2. 存儲(chǔ)協(xié)議 RCMessagePersistentCompatible

3. 內(nèi)容摘要協(xié)議 RCMessageContentView(可選)

其中,RCMessageCoding 主要有三個(gè)功能:提供消息唯一標(biāo)識(shí)符、消息發(fā)送時(shí)將消息中的所有信息編碼為 json 數(shù)據(jù)傳輸、消息接收時(shí)將 json 數(shù)據(jù)解碼還原為消息對(duì)象。

RCMessagePersistentCompatible 用于確定消息內(nèi)容的存儲(chǔ)策略,指明此消息類型在本地是否存儲(chǔ)、是否計(jì)入未讀消息數(shù)。

RCMessageContentView 用于在會(huì)話列表和本地通知中顯示消息的摘要。

最后在初始化融云的時(shí)候完成注冊(cè)。

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

1.2.2. 自定義消息 Cell 注冊(cè)并顯示

如果消息不需要顯示頭像,請(qǐng)繼承 RCMessageBaseCell。如果需要顯示,請(qǐng)繼承 RCMessageCell。

請(qǐng)?jiān)诔跏蓟椒ㄖ袑?shí)現(xiàn) Cell 的布局,并重寫(xiě)下面方法來(lái)返回 Cell 的 Size:

+ (CGSize)sizeForMessageModel:(RCMessageModel *)model

? ? ? ?withCollectionViewWidth:(CGFloat)collectionViewWidth

? ? ? ? ? referenceExtraHeight:(CGFloat)extraHeight;

然后在聊天試圖頁(yè)面用一下方法進(jìn)行cell的注冊(cè),以及與消息的綁定。

[self registerClass:[WMRCRecommendDoctorCell class]

? ? ? ? forMessageClass:[WMRCRecommendDoctorMessage class]];

2:原理的方面都已經(jīng)說(shuō)完了,下面直接粗暴的上代碼吧。

2.1 自定義消息體WMRCRecommendDoctorMessage(醫(yī)生名片)

申明一個(gè)標(biāo)志:這個(gè)標(biāo)志是我們發(fā)送,接收,以及和安卓 H5互發(fā)消息時(shí)候的依據(jù)。

''#define? ? WMRCRecommendDoctorMessageTypeIdentifier @"RCD:WMRecommendDoctorMsg"

根據(jù)需求 申明需要傳輸?shù)淖侄?/p>

/*! ?醫(yī)生頭像 字符串信息 ?*/

@property(nonatomic, strong) NSString *doctorHeader;

/*! 醫(yī)生名字 */

?@property(nonatomic, strong) NSString *doctorName;

?/*! 醫(yī)生科室 */

@property(nonatomic, strong) NSString *doctorSection;

?/*! ?預(yù)留附加信息 */

@property(nonatomic, strong) NSString *extra;

申明消息的初始話方法

/*! ?初始化測(cè)試消息

@param content 文本內(nèi)容

? @return? ? ? ? 測(cè)試消息對(duì)象 */

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

在.m中實(shí)現(xiàn)以下方法

///初始化

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

}

消息是否存儲(chǔ),是否計(jì)入未讀數(shù)

?+ (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"];

}

將消息內(nèi)容編碼成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解碼生成消息內(nèi)容

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

? ? ? ? ?}

? ? ?}

?}


會(huì)話列表中顯示的摘要

?- (NSString *)conversationDigest {

? ? ?return self.doctorName;

?}

消息的類型名

?+ (NSString *)getObjectName {

? ? ?return WMRCRecommendDoctorMessageTypeIdentifier;

?}

?2.2 自定義消息體WMRCInquiryMessageCell

根據(jù)需求申明變量

/*! 醫(yī)生頭像 */

?@property(strong, nonatomic) UIImageView *headerImageView;

?/*! 醫(yī)生姓名 */

?@property(strong, nonatomic) UILabel *nameLable;

?/*! 醫(yī)生科室 */

?@property(strong, nonatomic)UILabel *sectionLable;

?/*! 背景View */

?@property(nonatomic, strong) UIImageView *bubbleBackgroundView;

在.m中聲明一些全局變量 方便日后容易改動(dòng)

#define kheight 90? ? //名片的高度

?#define kwidth? 220? //名片的寬度

?#define kSpacing 7? ? //個(gè)控件之間的間隔

?#define kBubbleSharp 10 //氣泡尖尖的寬度

?#define kheaderHeight 60 //頭像的寬高

當(dāng)應(yīng)用自定義消息時(shí),必須實(shí)現(xiàn)該方法來(lái)返回cell的Size。

其中,extraHeight是Cell根據(jù)界面上下文,需要額外顯示的高度(比如時(shí)間、用戶名的高度等)。

一般而言,Cell的高度應(yīng)該是內(nèi)容顯示的高度再加上extraHeight的高度。

+ (CGSize)sizeForMessageModel:(RCMessageModel *)model

? ?withCollectionViewWidth:(CGFloat)collectionViewWidth

?referenceExtraHeight:(CGFloat)extraHeight {

//由于名片的高度,寬度一定 所以 下面這句代碼是沒(méi)有用途的

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

?}

創(chuàng)建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方法獲取數(shù)據(jù)

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

?[super setDataModel:model];

?[self setAutoLayout];

}

根據(jù)model對(duì)控件在cell上布局,其中分為接收方和發(fā)送方

?-(void)setAutoLayout {

?//創(chuàng)建控件

?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 是不對(duì)的)

?CGSize bubbleBackgroundViewSize =CGSizeMake(kwidth, kheight);

?//消息內(nèi)容的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);

?//消息內(nèi)容的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);

?//自己發(fā)消息

?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);

?//消息內(nèi)容的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)];

?}

?}

點(diǎn)擊問(wèn)題部分的手勢(shì),利用這個(gè)在視圖頁(yè)面進(jìn)行交互

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

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

? ? ? ? ?[self.delegate didTapMessageCell:self.model];

? ? ?}

?}

長(zhǎng)按手勢(shì),利用這個(gè)在視圖頁(yè)面進(jìn)行交互

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

? ? ?}

?}


效果圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容