最近把公司项目的聊天模块从”XMPP”转到”网易云信”官网、github。在转的过程中,上手很快,基本上没遇到什么难题,很多程度上感谢云信的NIMKit。以前也接触过几个IM SDK服务商的代码,那个时候看他们的代码根本没什么欲望,但这次看云信的代码有种被吸引的感觉,恨不得一下子把它的代码全部看完,封装的很好,扩展性很强(ps:就我目前的水平只能说出这些优点)。对于一般的聊天UI完全可以满足,就算不用网易的IM SDK,但他们的代码真的值得一下(尽管他们的UIKit代码注释比较少)。 Base tipscell的组成结构对于聊天”MessageCell”的介绍,一定要记住下面这张图片,以及相关参数的解释。1 n8 `! t* U; T- ?4 y$ m* }5 I
nimkit_cell . U- ?# p, P# h5 q, I# M% U6 M
- 蓝色区域:为具体内容,如文字 UILabel ,图片 UIImageView 等 。(对应的NIMMessageModel对象的contentSize属性)。注:NIMMessageModel为消息(NIMMessage) 在NIMKit中的封装。这个封装主要是为了对计算结果和布局配置进行缓存,以避免反复的计算和读取相同的信息,从而提高应用性能。
- 绿色区域:为消息的气泡,具体的内容和气泡之间会有一定的内间距,这里为 contentViewInsets 。(对应的NIMMessageModel对象的contentViewInsets属性)
- 紫色区域:为整个 UITableViewCell ,具体的气泡和整个cell会有一定的内间距,这里为 cellInsets 。(对应的NIMMessageModel对象的bubbleViewInsets属性)
# T y2 W) S. m
config配置协议在聊天界面有几个config配置代理,先熟悉一下。 - NIMSessionConfig:消息对应的session配置。如:录音、输入框、表情、更多等操作的选择;点击”+”号出来的多媒体按钮;是否禁用输入控件;输入控件的最大长度;输入控件的placeholder;一次最多消息的消息内容;间隔多久显示时间;语音红点是否禁用;是否自动切换成听筒模式;是否自动获取历史消息;消息数据提供器;消息的排版配置等。可以说这个是贯穿整个聊天模块的配置,修改聊天界面一般就得调整这里。
- NIMCellLayoutConfig:消息对应的布局配置。我们可以在这个config里面根据消息类型是否显示头像、姓名、头像与姓名之间的margin等;然后你会在项目里面看到自定义消息类型对应的NTESSessionCustomLayoutConfig,以及default默认的配置NIMCellLayoutDefaultConfig;
- NIMSessionContentConfig:消息内容配置。这个配置主要是为NIMSessionMessageContentView(请看下面对 聊天 NIMMessageCell.h 的介绍)对象为设置的。5 B" f- s: X3 w9 W' A% ?
聊天 NIMMessageCell.h先来看看头文件定义的属性; U, Z v1 y6 v. ]+ Y
- @property (nonatomic, strong) NIMAvatarImageView *headImageView;9 G/ ?! ]/ n: x% b6 R, t1 G
- @property (nonatomic, strong) UILabel *nameLabel; //姓名(群显示 个人不显示)
3 A7 ~8 N2 w6 B - @property (nonatomic, strong) NIMSessionMessageContentView *bubbleView; //内容区域
1 O" P) i% @" I; w$ J1 ~, ^ - @property (nonatomic, strong) UIActivityIndicatorView *traningActivityIndicator; //发送loading: Y0 F/ k9 X: u6 P2 Z
- @property (nonatomic, strong) UIButton *retryButton; //重试& M/ G% `, @* \& Q* ~
- @property (nonatomic, strong) NIMBadgeView *audioPlayedIcon; //语音未读红点
复制代码NIMSessionMessageContentView,顾名思义就是MessageCell的内容View(包括下面的bubble气泡View)。而 NIMSessionContentConfig 配置主要是配置 contentSize、contentViewInsets以及这个配置所应的 messageContentView 类名(NIMSessionMessageContentView的子类,每种聊天类型对应一个messageContentView)。注意,这里并没有提到 bubbleViewInsets,因为气泡隔cell的距离不会因不同类型而改变,我们只需在 cellLayoutConfig 里面处理即可,当然想要做到不同的话,也可以在 NIMSessionContentConfig 配置里面增加一个协议方法。注意 NIMSessionMessageContentView 是继承自 UIControl,这样不仅能处理点击事件,还能很好的处理点击高亮的效果。 NIMSessionViewController(聊天回话控制器基类)先来看看最重要的计算高度方法
/ i) ~! O H5 Z" c3 k5 I( z$ A! M - - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath' Q& M% j5 U* B1 Q. T
- {0 I t e! G4 S- s Y8 g
- CGFloat cellHeight = 0;% ^' f/ l8 K6 L$ Y8 b. Y% I
- id modelInArray = [[_sessionDatasource modelArray] objectAtIndex:indexPath.row];
: R7 y- C" W: [% ^/ C/ |7 v - if ([modelInArray isKindOfClass:[NIMMessageModel class]])
Z5 p$ }7 [6 }6 z. @( B* h - {
/ P& \, m; ^+ O1 l# [2 N# T+ }% s/ v - NIMMessageModel *model = (NIMMessageModel *)modelInArray;- _* y0 `% N' q4 U
- NSAssert([model respondsToSelector:@selector(contentSize)], @"config must have a cell height value!!!");0 O# Z6 F# p0 x1 ?0 e+ w6 b
- [self layoutConfig:model];: G" y; U4 ?) v7 ]! a. z( Y* E
- CGSize size = model.contentSize;& s+ a- M `% p. D! m/ [5 z
- UIEdgeInsets contentViewInsets = model.contentViewInsets;
6 C9 l5 F$ E g( g - UIEdgeInsets bubbleViewInsets = model.bubbleViewInsets;5 ]9 W" l' v+ i+ R$ L& ~4 I! w3 e
- cellHeight = size.height + contentViewInsets.top + contentViewInsets.bottom + bubbleViewInsets.top + bubbleViewInsets.bottom;# I4 Y; A+ A/ ?# A( x
- }; W4 w1 u9 R9 z/ `' f
- else if ([modelInArray isKindOfClass:[NIMTimestampModel class]])3 \3 o9 l6 E( J0 R' |8 r# q
- {
3 g. \# c- o# L+ b) R' L9 i - cellHeight = [modelInArray height];# y) _4 G) O8 b. R2 S" F( C0 S
- }# o4 t$ c$ w. |6 D
- else; R8 o: t! p0 ?7 n& c6 p9 l8 F
- {
' Q+ i2 e, Q) D% F- h3 j: e - NSAssert(0, @"not support model");) V1 l/ m+ C! l) S
- }3 Z5 b( O! V* \4 D( U, F, W% D
- return cellHeight;
! R& {4 N# g; T% H! ~' d, y - }
复制代码某个数据源所对应的高度就是三个颜色区域的高度之和(contentSize.height + contentViewInsets.top + contentViewInsets.bottom + bubbleViewInsets.top + bubbleViewInsets.bottom)。' H" {) h5 [& U) U9 e! V8 U" f
然后我们在来看看layoutConfig:方法:
* H" M* W$ B. e2 e) B- Z - - (void)layoutConfig:(NIMMessageModel *)model{
2 g) r" `( U( k0 p4 V+ D - model.sessionConfig = self.sessionConfig;
+ N% [) ^+ s3 S- y9 J - if (model.layoutConfig == nil)
# z5 [+ f& H7 r; ~( y) V - {
0 o2 j/ X2 J2 h% v- i; |0 ^ - id layoutConfig = nil;# R! E4 n* n* ?- ^- w6 A: j, d
- if ([self.sessionConfig respondsToSelector:@selector(layoutConfigWithMessage:)]) {9 T: x$ k$ G/ Q% _: M$ ?7 o- \
- layoutConfig = [self.sessionConfig layoutConfigWithMessage:model.message];- v, J9 U6 f" w |
- }% P. {# {$ H; X! P: N
- if (!layoutConfig) {
; y8 ~ ~- x; O& d1 U8 e - layoutConfig = [NIMDefaultValueMaker sharedMaker].cellLayoutDefaultConfig; I; h2 d: a V, y& R$ a& C
- }0 |) ^9 C& p! M$ E- U2 u
- model.layoutConfig = layoutConfig;: i9 P" V4 }7 [& [: s
- }* I" C+ Y5 j" n
- [model calculateContent:self.tableView.nim_width];
9 N! {$ u- f' J. S8 x! ?: s8 m& D6 X - }
复制代码其实这里就是,先配置model的sessionConfig,然后配置layoutConfig,配置完后就去计算该model所对应内容的contentSize。注:layoutConfigWithMessage:方法是自定义消息类型需要处理,还有记得在写代码中做好判nil的处理,如果为nil的话给default值。 好了,现在到了一个我当时比较蛋疼的地方了,请看下图
& t; g- _& x0 a* d1 b
Image2+ r6 }% ` O1 \0 t1 p( ^2 p) z% h. x
看到很多的方法,仔细看看,除了layoutConfig的配置方法以外,还有很多Attachment(Attachment 是属于自定义消息的配置协议)结尾的方法,其实这里应该只会提示NIMCellLayoutDefaultConfig和NTESSessionCustomLayoutConfig(NTESChatroomCellLayoutConfig聊天室的布局配置请忽略)才对,它们只是方法名相同,应该是Xcode抽风而导致的。 NIMCellLayoutDefaultConfig计算contentSize先看三个相关部分的代码 NIMCellLayoutDefaultConfig- - (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)cellWidth{7 |, Y3 ]% a; Z3 _0 B* J$ `
-
7 {4 U, U5 Q/ H9 y0 q% O - idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];& |7 O/ z% Z# L* S( p* h
- return [config contentSize:cellWidth];
" L/ s" B; v4 @' a - }. Q) R, n8 o9 q" L, i
- ' K# u! P ~2 B" E5 w4 Z
- - (NSString *)cellContent:(NIMMessageModel *)model{* c$ z' R3 [1 W( q2 W+ x, P) l8 H1 g) v5 [
-
* J. N; a' y4 [) E) ]. | - idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];! U8 r( l- \ N5 W1 E/ @
- NSString *cellContent = [config cellContent];
8 @, w o) w" p9 p& | - return cellContent ? : @"NIMSessionUnknowContentView";
: M( A6 o) K- x9 @6 x - }. N! N5 [# d( O, _# G; W J
- " L% B+ l# x, G- R4 N2 G. [- u2 [. @
; Z( l5 Q$ ^2 V2 D4 T6 @1 h- p- - (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model{
% R, A' Q& A8 l - idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];
" @+ _6 s, h7 {4 S9 a - return [config contentViewInsets];; I/ C8 j- @5 V! ^7 s4 B% E
- }
复制代码 NIMSessionContentConfigFactory- - (instancetype)init8 ]( M+ l) C& q
- {
7 _5 c" w/ l0 u4 k6 F- B. h - if (self = [super init])
2 f. D5 M! r# m, w) e, k - {
" x7 ?5 G0 O# d3 p# D7 \# M& ~8 ] - _dict = @{@(NIMMessageTypeText) : [NIMTextContentConfig new],
`# g6 m! E; O" O: v9 b - @(NIMMessageTypeImage) : [NIMImageContentConfig new],
6 e; F) n8 q. h: ^1 C L - @(NIMMessageTypeAudio) : [NIMAudioContentConfig new],) M& j3 m+ d% S: B; z- `! Z M: N
- @(NIMMessageTypeVideo) : [NIMVideoContentConfig new],% D4 k# ?. G* S( @# e( r& j' A4 U0 u
- @(NIMMessageTypeFile) : [NIMFileContentConfig new], y; u6 f+ c/ A: a6 F% I0 [$ l
- @(NIMMessageTypeLocation) : [NIMLocationContentConfig new],
: Y, _; a; O1 C, Y9 M0 H - @(NIMMessageTypeNotification) : [NIMNotificationContentConfig new],# |) d' a t8 w7 R$ s6 p1 Q/ e
- @(NIMMessageTypeTip) : [NIMTipContentConfig new]};
. }$ l" y/ _; I8 J0 l* v+ x - }& F' i5 e$ ~, R* D* r
- return self;; G/ z! B7 A0 h" X
- }
" d+ l# n' m$ ^
4 }$ n" L, S' D7 m% }: d- - (id)configBy:(NIMMessage *)message, F9 E8 O/ k V" r) _. p# I( u% U
- {% C- \' T* I6 d8 f6 O1 b& N# j
- NIMMessageType type = message.messageType;
3 z8 ~* V+ L. c4 c" q, v - idconfig = [_dict objectForKey:@(type)];
, r8 `! ^5 ?4 L- R4 D - if (config == nil)
6 o6 j7 x( B) {' a - {
. |7 M1 D. B* S: V- ?# m% F - config = [NIMUnsupportContentConfig sharedConfig];: [4 S* q" r8 I# k1 F' c* u
- }9 |! n0 }" b6 z/ s. [
- if ([config isKindOfClass:[NIMBaseSessionContentConfig class]]) k$ E1 a0 {3 T+ R; p, F: p2 s
- {/ M) J+ y) |7 S' |
- [(NIMBaseSessionContentConfig *)config setMessage:message];$ Z- @" H1 q" Y0 @+ N; W
- }
: _# ]; i% N% b) P+ x - return config;9 q# p8 n/ K% X! o$ ^, a
- }
复制代码 NIMImageContentConfig- #import "NIMBaseSessionContentConfig.h"6 m1 Y Y, c- {& M
7 [5 V0 K; T' u- K- @interface NIMTextContentConfig : NIMBaseSessionContentConfig
, I) J2 `$ x, e8 N - ' t7 o4 C- S; N) j6 f
- @end
复制代码- @interface NIMTextContentConfig()
0 ~5 S7 {4 G- o, @7 y* V) ]
3 b1 |" ~: n2 N' h6 `9 |7 E$ e2 T. ^8 g- @property (nonatomic,strong) NIMAttributedLabel *label;. j7 M* j1 m' D
- ' Y+ S) F$ P1 ~, ]0 W }, a
- @end
, ^+ E% z7 u' P1 ~8 w# |, o$ M W - : W) o/ L0 ^6 ?" Q' V
- " J* L/ c: a( o# k: O
- @implementation NIMTextContentConfig
2 t- S2 L4 g) C1 K5 w* K6 u t4 ^
9 ~. X6 |" B4 K5 c0 R- - (CGSize)contentSize:(CGFloat)cellWidth
* Y a* j3 L4 y" D# t' @ - {
2 C$ Y/ R7 C4 q* v) }, m - NSString *text = self.message.text;
$ \! a6 |7 M. {- F# z( x$ I0 v - [self.label nim_setText:text];# s) u3 h1 J- ~! w& |" n. q
- 6 R2 _2 M: I4 m
- CGFloat msgBubbleMaxWidth = (cellWidth - 130);
$ m" U! ?7 ? B# x# j - CGFloat bubbleLeftToContent = 14;1 D! _" J' T" | ^ T# E, u c" b4 {& V
- CGFloat contentRightToBubble = 14;! `" N" G, L ~ r: s
- CGFloat msgContentMaxWidth = (msgBubbleMaxWidth - contentRightToBubble - bubbleLeftToContent);
2 q1 A- W% O& \0 c. q* m* Z' G - return [self.label sizeThatFits:CGSizeMake(msgContentMaxWidth, CGFLOAT_MAX)];
9 F! [2 t2 i$ ?0 b! o5 |& l4 i - }
- I$ d0 h7 a1 f$ Z4 w
& `) |0 i, V* I) Z- - (NSString *)cellContent7 O4 Q( D$ k2 @
- {
2 A4 K x1 W9 `) d8 t - return @"NIMSessionTextContentView";9 h; q- B8 x/ J: \
- }1 _: m; ~( o0 i, C' a" k
/ R6 M9 }+ ~2 i/ e3 r/ f4 G" _- - (UIEdgeInsets)contentViewInsets. _5 `% H0 w, r# x1 _, O- w& J
- {4 z% s$ W8 P& R8 _$ q4 W5 Y' R8 o
- return self.message.isOutgoingMsg ? UIEdgeInsetsMake(11,11,9,15) : UIEdgeInsetsMake(11,15,9,9);
. g! G) X) z5 k4 q - }2 ]' i+ {; c, d
' w) e5 U9 c( m5 V/ { x
. |* B( |9 ?! U, r) m2 c# { B2 x- - (NIMAttributedLabel *)label
3 B6 `1 i7 }' R$ K0 w - {6 i5 h8 E0 r% f9 ?1 o
- if (_label) {' H9 |. F8 l7 S% W5 N; y
- return _label;( R7 F, W, u8 ], m, @) z* t/ _
- }
* [. ~& V7 [2 I+ c1 I7 L - _label = [[NIMAttributedLabel alloc] initWithFrame:CGRectZero];( q# {9 \) H7 o% ], U$ g6 V$ t
- _label.font = [UIFont systemFontOfSize:NIMKit_Message_Font_Size];
4 {. I' i- \( \0 M, N - return _label;
, Y! t& X: s' t+ P' i# w - }
, l( N$ w8 e" n - @end
复制代码这里就是实现了NIMSessionContentConfig配置协议,我举例一个文本消息类型的sessionContentView的处理方式,其他类型是一样的处理方法,实现相关配置协议方法即可。你可能会想到如果某个sessionContentView上面的元素有很多时该怎么处理,我该不会把某个sessionContentView的元素都定义一次,然后全部赋值再计算contentSize么?我将会在说自定义消息类型的时候谈谈我简单的处理方式。
+ m" K7 b$ J: U9 E5 _4 e这里我个人觉得有两点可以改变一下。 - NIMBaseSessionContentConfig的NIMMessage对象应该改为NIMMessageModel对象比较好。因为我需要用到contentSize,根据contentSize来设置控件的宽度适应屏幕。所以我在自定义的消息里面,将NTESCustomAttachmentInfo协议需要传入的NIMMessage对象改为NIMMessageModel对象。
- 在返回contentView类名时,改为NSStringFromClass([NIMSessionTextContentView Class])会好点,怕输入字符串时时产生错误嘛。6 ? m4 ^# d2 s. r6 q- a
在NIMSessionContentConfigFactory类里面定义了基本消息类型所对应的contentConfig配置协议(注意,在云信demo里面,每个sessionContentView都对应一个sessionContentConfig)。请看NIMUnsupportContentConfig判nil处理,如果没有这段判断处理,你在添加自定义消息时候,忘记在 NTESSessionCustomLayoutConfig类的supportAttachmentType方法里面添加你的自定义消息,程序就会崩溃。ps:防止崩溃,请从细节做起,谢谢! 那NIMCellLayoutDefaultConfig计算contentSize就简单明了了,就是调用相关 sessionContentConfig 的方法嘛。 NNTESSessionCustomContentConfig计算contentSize当我们看到NTESSessionCustomLayoutConfig类时,有两个地方是值得我们注意,也是与NIMCellLayoutDefaultConfig不同的地方。 - 一个NTESSessionCustomContentConfig类的属性
- supportAttachmentType 内部方法,用来获取customLayoutConfig直接的类型。
+ N2 O' B P: Q/ F; Y9 e
NTESSessionCustomContentConfig它有一个NIMMessage类型的public属性,而在介绍NIMBaseSessionContentConfig配置协议时,我有说过建议将它的NIMMessage对象改为NIMMessageModel对象,在这里我也同样建议,原因上面有提过。8 k2 S" G$ r' X
请看它的.m文件:
$ j% O1 o; X m - @interface NTESSessionCustomContentConfig()1 x7 ]/ A1 c4 ?' Y) L1 v E
- 8 n2 O) U* q3 d( |* y: b
- @property (nonatomic, strong) id attachmentInfo;7 |- T8 B$ A- j! D, k
4 T7 a" t: j9 S: w4 k( ^0 F$ G- @end
7 i1 M4 t; P' s" f
! d0 ?0 R3 k$ J7 k9 e+ D) H" Z2 z- @implementation NTESSessionCustomContentConfig
& C. ?3 q. ]& |6 S5 Z3 I* g+ U" F - , H: j: d. V _1 a! G5 V
- - (void)setMessage:(NIMMessage *)message3 t( V. y' T2 I
- {
* J3 ^" {- |! l - NIMCustomObject *object = message.messageObject;8 G1 u" a# l, X$ K; ~. l+ y( s5 I5 Z @
- _message = message;9 v, w9 T! z& o/ T7 p" m5 V) G! p
- _attachmentInfo = (id)object.attachment;6 x0 e& Z$ z3 N9 z* r' J8 X2 h
- }
4 v+ r+ P2 V1 a2 w) \
" p; Q- V; }, D7 K6 ?% l& Z- - (CGSize)contentSize:(CGFloat)cellWidth7 o K, F/ q8 s
- {6 {% M+ ?! i6 s. |+ x& ^ m
- return [self.attachmentInfo contentSize:self.message cellWidth:cellWidth];2 |3 }* b; i: S* j
- }
- D$ ~+ V# z0 M' {* o7 h - + z8 C1 l, B k' h/ E& G
- - (NSString *)cellContent& b' D( D7 u8 o4 p/ r4 Q+ D
- {# o/ N& s! A% k( Z; U, s
- return [self.attachmentInfo cellContent:self.message];
: s5 I' G9 s1 K - }
+ f" y, q1 L$ y0 `2 M - * `$ |* O7 L6 @( _
- - (UIEdgeInsets)contentViewInsets" F. B$ h7 n# {, { c, r$ j
- {
7 J& S( b$ C. U3 O - return [self.attachmentInfo contentViewInsets:self.message];+ W' n U# c8 K3 ]. T* P5 _
- }
2 [/ \& L S T% E3 }4 e
# |+ ~, p9 z, ]: \3 J& }- @end
复制代码attachmentInfo对象代表不同类型的自定义消息,只要它遵守NTESCustomAttachmentInfo协议即可。(ps:其实NTESCustomAttachmentInfo协议就相当于上面基本消息类型所对应的NIMSessionContentConfig协议;注:这里所谓的基本消息类型,即云信SDK已定义的消息类型,相对于自定义消息类型而言而已。) 下面来看看 NTESCustomAttachmentInfo 协议(已添加注释)。
3 f& |8 ~& q1 |- ?# H4 G8 p+ G - @protocol NTESCustomAttachmentInfo : R' Y/ c+ h- G1 y
- / O/ d# d/ G [* X# h7 v
- @optional! u8 Z# ^5 {2 e* _5 O
- /// contentView类名
# a; e3 D# ~3 {# x$ `* p - - (NSString *)cellContent:(NIMMessage *)message;
7 y; J1 L+ x4 Q# f+ e& ~# g9 e - /// contentSize
+ c3 o, _8 ~" R9 U - - (CGSize)contentSize:(NIMMessage *)message cellWidth:(CGFloat)width;
5 L( h( ]; I Z% n. L6 R6 x - /// 内容距离bubble气泡的相关距离
! k4 x4 N$ F! z4 s# U" o3 h - - (UIEdgeInsets)contentViewInsets:(NIMMessage *)message;+ f4 u5 |% ~% `' r8 {6 d
- /// 格式化消息 某些消息需要在最近回话列表特殊文字 如:收到一段文字,但是需要显示[系统消息]
! s! k9 v) m- P3 d+ S7 G6 f; ^ - - (NSString *)formatedMessage;
! K6 b: A( t8 O4 l+ w8 b; \( O - /// 封面图片 如果一个视频 得显示一张图片在界面6 k: c' E$ J: k/ F' b$ D* m( l
- - (UIImage *)showCoverImage;, n# q# d O6 \! e/ g' ~
- /// 设置封面图片+ o% C/ ~$ D3 X) }, k
- - (void)setShowCoverImage:(UIImage *)image;
复制代码在这里我提出两点建议 - NIMMessage对象改为NIMMessageModel对象;
- cellContent:、contentSize: cellWidth:、contentViewInsets:这三个方法改为@required类型的;方法名前面加上attachmentInfo与NIMSessionContentConfig协议的相关方法作为区分。
4 H7 [$ c' E7 R: U" {* F
复杂自定义sessionContentView的简单处理方式上面在介绍NIMBaseSessionContentConfig配置协议时,我有提到如果某个sessionContentView上面的元素有很多时该怎么处理。下面我说说我的处理方式。 - 把计算contentSize和contentViewInsets的方法丢到contentView里面,这样一来,那么只要在attachMentInfo里面调用所属contentView的计算方法。
我会在NIMSessionMessageContentView类里面增加两个方法 - - (CGSize)attachmentInfoViewContentSize:(NIMMessageModel *)messageModel cellWidth:(CGFloat)width;6 H# g9 \' A$ Z
- - (UIEdgeInsets)attachmentInfoViewcontentViewInsets:(NIMMessageModel *)messageModel;
复制代码 % q. l$ \: ?: _, J: m
在具体的contentView里面,我定义方法,它有一个Bool类型的isInit(是否初始化)入参,在这个方法里面我创建和实例变量一样的临时变量,当attachmentInfoViewContentSize: cellWidth方法调用它时,我只是为了方便计算contentSize,如果是initSessionMessageContentView方法调用时,我就将相应的临时变量赋值给例变量。
7 G/ \5 X8 V/ m3 p8 t/ y' C5 x
原文链接:http://joakimliu.github.io/2016/03/27/NIMKit%E6%B5%85%E6%9E%90/ |