用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

发帖

网易云信IM云服务,NIMKit浅析

[复制链接]
  • TA的每日心情
    开心
    2020-8-4 16:45
  • 27

    主题

    33

    帖子

    645

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    645
    发表于 2016-3-27 00:00:00
    最近把公司项目的聊天模块从”XMPP”转到”网易云信”官网github。在转的过程中,上手很快,基本上没遇到什么难题,很多程度上感谢云信的NIMKit。以前也接触过几个IM SDK服务商的代码,那个时候看他们的代码根本没什么欲望,但这次看云信的代码有种被吸引的感觉,恨不得一下子把它的代码全部看完,封装的很好,扩展性很强(ps:就我目前的水平只能说出这些优点)。对于一般的聊天UI完全可以满足,就算不用网易的IM SDK,但他们的代码真的值得一下(尽管他们的UIKit代码注释比较少)。
    在看本文之前,请先看一下他们官方的github简介
    Base tipscell的组成结构
    对于聊天”MessageCell”的介绍,一定要记住下面这张图片,以及相关参数的解释。1 n8 `! t* U; T- ?4 y$ m* }5 I
    005IevIrjw1f2bf6cvkjqj31bu0iktbg.jpg 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
    1. @property (nonatomic, strong) NIMAvatarImageView *headImageView;9 G/ ?! ]/ n: x% b6 R, t1 G
    2. @property (nonatomic, strong) UILabel *nameLabel;                                 //姓名(群显示 个人不显示)
      3 A7 ~8 N2 w6 B
    3. @property (nonatomic, strong) NIMSessionMessageContentView *bubbleView;           //内容区域
      1 O" P) i% @" I; w$ J1 ~, ^
    4. @property (nonatomic, strong) UIActivityIndicatorView *traningActivityIndicator;  //发送loading: Y0 F/ k9 X: u6 P2 Z
    5. @property (nonatomic, strong) UIButton *retryButton;                              //重试& M/ G% `, @* \& Q* ~
    6. @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
    1. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath' Q& M% j5 U* B1 Q. T
    2. {0 I  t  e! G4 S- s  Y8 g
    3.     CGFloat cellHeight = 0;% ^' f/ l8 K6 L$ Y8 b. Y% I
    4.     id modelInArray = [[_sessionDatasource modelArray] objectAtIndex:indexPath.row];
      : R7 y- C" W: [% ^/ C/ |7 v
    5.     if ([modelInArray isKindOfClass:[NIMMessageModel class]])
        Z5 p$ }7 [6 }6 z. @( B* h
    6.     {
      / P& \, m; ^+ O1 l# [2 N# T+ }% s/ v
    7.         NIMMessageModel *model = (NIMMessageModel *)modelInArray;- _* y0 `% N' q4 U
    8.         NSAssert([model respondsToSelector:@selector(contentSize)], @"config must have a cell height value!!!");0 O# Z6 F# p0 x1 ?0 e+ w6 b
    9.         [self layoutConfig:model];: G" y; U4 ?) v7 ]! a. z( Y* E
    10.         CGSize size = model.contentSize;& s+ a- M  `% p. D! m/ [5 z
    11.         UIEdgeInsets contentViewInsets = model.contentViewInsets;
      6 C9 l5 F$ E  g( g
    12.         UIEdgeInsets bubbleViewInsets  = model.bubbleViewInsets;5 ]9 W" l' v+ i+ R$ L& ~4 I! w3 e
    13.         cellHeight = size.height + contentViewInsets.top + contentViewInsets.bottom + bubbleViewInsets.top + bubbleViewInsets.bottom;# I4 Y; A+ A/ ?# A( x
    14.     }; W4 w1 u9 R9 z/ `' f
    15.     else if ([modelInArray isKindOfClass:[NIMTimestampModel class]])3 \3 o9 l6 E( J0 R' |8 r# q
    16.     {
      3 g. \# c- o# L+ b) R' L9 i
    17.         cellHeight = [modelInArray height];# y) _4 G) O8 b. R2 S" F( C0 S
    18.     }# o4 t$ c$ w. |6 D
    19.     else; R8 o: t! p0 ?7 n& c6 p9 l8 F
    20.     {
      ' Q+ i2 e, Q) D% F- h3 j: e
    21.         NSAssert(0, @"not support model");) V1 l/ m+ C! l) S
    22.     }3 Z5 b( O! V* \4 D( U, F, W% D
    23.     return cellHeight;
      ! R& {4 N# g; T% H! ~' d, y
    24. }
    复制代码
    某个数据源所对应的高度就是三个颜色区域的高度之和(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
    1. - (void)layoutConfig:(NIMMessageModel *)model{
      2 g) r" `( U( k0 p4 V+ D
    2.     model.sessionConfig = self.sessionConfig;
      + N% [) ^+ s3 S- y9 J
    3.     if (model.layoutConfig == nil)
      # z5 [+ f& H7 r; ~( y) V
    4.     {
      0 o2 j/ X2 J2 h% v- i; |0 ^
    5.         id layoutConfig = nil;# R! E4 n* n* ?- ^- w6 A: j, d
    6.         if ([self.sessionConfig respondsToSelector:@selector(layoutConfigWithMessage:)]) {9 T: x$ k$ G/ Q% _: M$ ?7 o- \
    7.             layoutConfig = [self.sessionConfig layoutConfigWithMessage:model.message];- v, J9 U6 f" w  |
    8.         }% P. {# {$ H; X! P: N
    9.         if (!layoutConfig) {
      ; y8 ~  ~- x; O& d1 U8 e
    10.             layoutConfig = [NIMDefaultValueMaker sharedMaker].cellLayoutDefaultConfig;  I; h2 d: a  V, y& R$ a& C
    11.         }0 |) ^9 C& p! M$ E- U2 u
    12.         model.layoutConfig = layoutConfig;: i9 P" V4 }7 [& [: s
    13.     }* I" C+ Y5 j" n
    14.     [model calculateContent:self.tableView.nim_width];
      9 N! {$ u- f' J. S8 x! ?: s8 m& D6 X
    15. }
    复制代码
    其实这里就是,先配置model的sessionConfig,然后配置layoutConfig,配置完后就去计算该model所对应内容的contentSize。注:layoutConfigWithMessage:方法是自定义消息类型需要处理,还有记得在写代码中做好判nil的处理,如果为nil的话给default值。
    好了,现在到了一个我当时比较蛋疼的地方了,请看下图
    & t; g- _& x0 a* d1 b 005IevIrjw1f2bgtofy3yj30t50acdkr.jpg Image2+ r6 }% `  O1 \0 t1 p( ^2 p) z% h. x
    看到很多的方法,仔细看看,除了layoutConfig的配置方法以外,还有很多Attachment(Attachment 是属于自定义消息的配置协议)结尾的方法,其实这里应该只会提示NIMCellLayoutDefaultConfig和NTESSessionCustomLayoutConfig(NTESChatroomCellLayoutConfig聊天室的布局配置请忽略)才对,它们只是方法名相同,应该是Xcode抽风而导致的。
    NIMCellLayoutDefaultConfig计算contentSize
    先看三个相关部分的代码
    NIMCellLayoutDefaultConfig
    1. - (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)cellWidth{7 |, Y3 ]% a; Z3 _0 B* J$ `
    2.    
      7 {4 U, U5 Q/ H9 y0 q% O
    3.     idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];& |7 O/ z% Z# L* S( p* h
    4.     return [config contentSize:cellWidth];
      " L/ s" B; v4 @' a
    5. }. Q) R, n8 o9 q" L, i
    6. ' K# u! P  ~2 B" E5 w4 Z
    7. - (NSString *)cellContent:(NIMMessageModel *)model{* c$ z' R3 [1 W( q2 W+ x, P) l8 H1 g) v5 [
    8.    
      * J. N; a' y4 [) E) ]. |
    9.     idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];! U8 r( l- \  N5 W1 E/ @
    10.     NSString *cellContent = [config cellContent];
      8 @, w  o) w" p9 p& |
    11.     return cellContent ? : @"NIMSessionUnknowContentView";
      : M( A6 o) K- x9 @6 x
    12. }. N! N5 [# d( O, _# G; W  J
    13. " L% B+ l# x, G- R4 N2 G. [- u2 [. @

    14. ; Z( l5 Q$ ^2 V2 D4 T6 @1 h- p
    15. - (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model{
      % R, A' Q& A8 l
    16.     idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];
      " @+ _6 s, h7 {4 S9 a
    17.     return [config contentViewInsets];; I/ C8 j- @5 V! ^7 s4 B% E
    18. }
    复制代码
    NIMSessionContentConfigFactory
    1. - (instancetype)init8 ]( M+ l) C& q
    2. {
      7 _5 c" w/ l0 u4 k6 F- B. h
    3.     if (self = [super init])
      2 f. D5 M! r# m, w) e, k
    4.     {
      " x7 ?5 G0 O# d3 p# D7 \# M& ~8 ]
    5.         _dict = @{@(NIMMessageTypeText)         :       [NIMTextContentConfig new],
        `# g6 m! E; O" O: v9 b
    6.                   @(NIMMessageTypeImage)        :       [NIMImageContentConfig new],
      6 e; F) n8 q. h: ^1 C  L
    7.                   @(NIMMessageTypeAudio)        :       [NIMAudioContentConfig new],) M& j3 m+ d% S: B; z- `! Z  M: N
    8.                   @(NIMMessageTypeVideo)        :       [NIMVideoContentConfig new],% D4 k# ?. G* S( @# e( r& j' A4 U0 u
    9.                   @(NIMMessageTypeFile)         :       [NIMFileContentConfig new],  y; u6 f+ c/ A: a6 F% I0 [$ l
    10.                   @(NIMMessageTypeLocation)     :       [NIMLocationContentConfig new],
      : Y, _; a; O1 C, Y9 M0 H
    11.                   @(NIMMessageTypeNotification) :       [NIMNotificationContentConfig new],# |) d' a  t8 w7 R$ s6 p1 Q/ e
    12.                   @(NIMMessageTypeTip)          :       [NIMTipContentConfig new]};
      . }$ l" y/ _; I8 J0 l* v+ x
    13.     }& F' i5 e$ ~, R* D* r
    14.     return self;; G/ z! B7 A0 h" X
    15. }
      " d+ l# n' m$ ^

    16. 4 }$ n" L, S' D7 m% }: d
    17. - (id)configBy:(NIMMessage *)message, F9 E8 O/ k  V" r) _. p# I( u% U
    18. {% C- \' T* I6 d8 f6 O1 b& N# j
    19.     NIMMessageType type = message.messageType;
      3 z8 ~* V+ L. c4 c" q, v
    20.     idconfig = [_dict objectForKey:@(type)];
      , r8 `! ^5 ?4 L- R4 D
    21.     if (config == nil)
      6 o6 j7 x( B) {' a
    22.     {
      . |7 M1 D. B* S: V- ?# m% F
    23.         config = [NIMUnsupportContentConfig sharedConfig];: [4 S* q" r8 I# k1 F' c* u
    24.     }9 |! n0 }" b6 z/ s. [
    25.     if ([config isKindOfClass:[NIMBaseSessionContentConfig class]])  k$ E1 a0 {3 T+ R; p, F: p2 s
    26.     {/ M) J+ y) |7 S' |
    27.         [(NIMBaseSessionContentConfig *)config setMessage:message];$ Z- @" H1 q" Y0 @+ N; W
    28.     }
      : _# ]; i% N% b) P+ x
    29.     return config;9 q# p8 n/ K% X! o$ ^, a
    30. }
    复制代码
    NIMImageContentConfig
    1. #import "NIMBaseSessionContentConfig.h"6 m1 Y  Y, c- {& M

    2. 7 [5 V0 K; T' u- K
    3. @interface NIMTextContentConfig : NIMBaseSessionContentConfig
      , I) J2 `$ x, e8 N
    4. ' t7 o4 C- S; N) j6 f
    5. @end
    复制代码
    1. @interface NIMTextContentConfig()
      0 ~5 S7 {4 G- o, @7 y* V) ]

    2. 3 b1 |" ~: n2 N' h6 `9 |7 E$ e2 T. ^8 g
    3. @property (nonatomic,strong) NIMAttributedLabel *label;. j7 M* j1 m' D
    4. ' Y+ S) F$ P1 ~, ]0 W  }, a
    5. @end
      , ^+ E% z7 u' P1 ~8 w# |, o$ M  W
    6. : W) o/ L0 ^6 ?" Q' V
    7. " J* L/ c: a( o# k: O
    8. @implementation NIMTextContentConfig
      2 t- S2 L4 g) C1 K5 w* K6 u  t4 ^

    9. 9 ~. X6 |" B4 K5 c0 R
    10. - (CGSize)contentSize:(CGFloat)cellWidth
      * Y  a* j3 L4 y" D# t' @
    11. {
      2 C$ Y/ R7 C4 q* v) }, m
    12.     NSString *text = self.message.text;
      $ \! a6 |7 M. {- F# z( x$ I0 v
    13.     [self.label nim_setText:text];# s) u3 h1 J- ~! w& |" n. q
    14.     6 R2 _2 M: I4 m
    15.     CGFloat msgBubbleMaxWidth    = (cellWidth - 130);
      $ m" U! ?7 ?  B# x# j
    16.     CGFloat bubbleLeftToContent  = 14;1 D! _" J' T" |  ^  T# E, u  c" b4 {& V
    17.     CGFloat contentRightToBubble = 14;! `" N" G, L  ~  r: s
    18.     CGFloat msgContentMaxWidth = (msgBubbleMaxWidth - contentRightToBubble - bubbleLeftToContent);
      2 q1 A- W% O& \0 c. q* m* Z' G
    19.     return [self.label sizeThatFits:CGSizeMake(msgContentMaxWidth, CGFLOAT_MAX)];
      9 F! [2 t2 i$ ?0 b! o5 |& l4 i
    20. }
      - I$ d0 h7 a1 f$ Z4 w

    21. & `) |0 i, V* I) Z
    22. - (NSString *)cellContent7 O4 Q( D$ k2 @
    23. {
      2 A4 K  x1 W9 `) d8 t
    24.     return @"NIMSessionTextContentView";9 h; q- B8 x/ J: \
    25. }1 _: m; ~( o0 i, C' a" k

    26. / R6 M9 }+ ~2 i/ e3 r/ f4 G" _
    27. - (UIEdgeInsets)contentViewInsets. _5 `% H0 w, r# x1 _, O- w& J
    28. {4 z% s$ W8 P& R8 _$ q4 W5 Y' R8 o
    29.     return self.message.isOutgoingMsg ? UIEdgeInsetsMake(11,11,9,15) : UIEdgeInsetsMake(11,15,9,9);
      . g! G) X) z5 k4 q
    30. }2 ]' i+ {; c, d

    31. ' w) e5 U9 c( m5 V/ {  x

    32. . |* B( |9 ?! U, r) m2 c# {  B2 x
    33. - (NIMAttributedLabel *)label
      3 B6 `1 i7 }' R$ K0 w
    34. {6 i5 h8 E0 r% f9 ?1 o
    35.     if (_label) {' H9 |. F8 l7 S% W5 N; y
    36.         return _label;( R7 F, W, u8 ], m, @) z* t/ _
    37.     }
      * [. ~& V7 [2 I+ c1 I7 L
    38.     _label = [[NIMAttributedLabel alloc] initWithFrame:CGRectZero];( q# {9 \) H7 o% ], U$ g6 V$ t
    39.     _label.font = [UIFont systemFontOfSize:NIMKit_Message_Font_Size];
      4 {. I' i- \( \0 M, N
    40.     return _label;
      , Y! t& X: s' t+ P' i# w
    41. }
      , l( N$ w8 e" n
    42. @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
    1. @interface NTESSessionCustomContentConfig()1 x7 ]/ A1 c4 ?' Y) L1 v  E
    2. 8 n2 O) U* q3 d( |* y: b
    3. @property (nonatomic, strong) id attachmentInfo;7 |- T8 B$ A- j! D, k

    4. 4 T7 a" t: j9 S: w4 k( ^0 F$ G
    5. @end
      7 i1 M4 t; P' s" f

    6. ! d0 ?0 R3 k$ J7 k9 e+ D) H" Z2 z
    7. @implementation NTESSessionCustomContentConfig
      & C. ?3 q. ]& |6 S5 Z3 I* g+ U" F
    8. , H: j: d. V  _1 a! G5 V
    9. - (void)setMessage:(NIMMessage *)message3 t( V. y' T2 I
    10. {
      * J3 ^" {- |! l
    11.     NIMCustomObject *object = message.messageObject;8 G1 u" a# l, X$ K; ~. l+ y( s5 I5 Z  @
    12.     _message = message;9 v, w9 T! z& o/ T7 p" m5 V) G! p
    13.     _attachmentInfo = (id)object.attachment;6 x0 e& Z$ z3 N9 z* r' J8 X2 h
    14. }
      4 v+ r+ P2 V1 a2 w) \

    15. " p; Q- V; }, D7 K6 ?% l& Z
    16. - (CGSize)contentSize:(CGFloat)cellWidth7 o  K, F/ q8 s
    17. {6 {% M+ ?! i6 s. |+ x& ^  m
    18.     return [self.attachmentInfo contentSize:self.message cellWidth:cellWidth];2 |3 }* b; i: S* j
    19. }
      - D$ ~+ V# z0 M' {* o7 h
    20. + z8 C1 l, B  k' h/ E& G
    21. - (NSString *)cellContent& b' D( D7 u8 o4 p/ r4 Q+ D
    22. {# o/ N& s! A% k( Z; U, s
    23.     return [self.attachmentInfo cellContent:self.message];
      : s5 I' G9 s1 K
    24. }
      + f" y, q1 L$ y0 `2 M
    25. * `$ |* O7 L6 @( _
    26. - (UIEdgeInsets)contentViewInsets" F. B$ h7 n# {, {  c, r$ j
    27. {
      7 J& S( b$ C. U3 O
    28.     return [self.attachmentInfo contentViewInsets:self.message];+ W' n  U# c8 K3 ]. T* P5 _
    29. }
      2 [/ \& L  S  T% E3 }4 e

    30. # |+ ~, p9 z, ]: \3 J& }
    31. @end
    复制代码
    attachmentInfo对象代表不同类型的自定义消息,只要它遵守NTESCustomAttachmentInfo协议即可。(ps:其实NTESCustomAttachmentInfo协议就相当于上面基本消息类型所对应的NIMSessionContentConfig协议;注:这里所谓的基本消息类型,即云信SDK已定义的消息类型,相对于自定义消息类型而言而已。)
    下面来看看 NTESCustomAttachmentInfo 协议(已添加注释)。
    3 f& |8 ~& q1 |- ?# H4 G8 p+ G
    1. @protocol NTESCustomAttachmentInfo : R' Y/ c+ h- G1 y
    2. / O/ d# d/ G  [* X# h7 v
    3. @optional! u8 Z# ^5 {2 e* _5 O
    4. /// contentView类名
      # a; e3 D# ~3 {# x$ `* p
    5. - (NSString *)cellContent:(NIMMessage *)message;
      7 y; J1 L+ x4 Q# f+ e& ~# g9 e
    6. /// contentSize
      + c3 o, _8 ~" R9 U
    7. - (CGSize)contentSize:(NIMMessage *)message cellWidth:(CGFloat)width;
      5 L( h( ]; I  Z% n. L6 R6 x
    8. /// 内容距离bubble气泡的相关距离
      ! k4 x4 N$ F! z4 s# U" o3 h
    9. - (UIEdgeInsets)contentViewInsets:(NIMMessage *)message;+ f4 u5 |% ~% `' r8 {6 d
    10. /// 格式化消息 某些消息需要在最近回话列表特殊文字 如:收到一段文字,但是需要显示[系统消息]
      ! s! k9 v) m- P3 d+ S7 G6 f; ^
    11. - (NSString *)formatedMessage;
      ! K6 b: A( t8 O4 l+ w8 b; \( O
    12. /// 封面图片 如果一个视频 得显示一张图片在界面6 k: c' E$ J: k/ F' b$ D* m( l
    13. - (UIImage *)showCoverImage;, n# q# d  O6 \! e/ g' ~
    14. /// 设置封面图片+ o% C/ ~$ D3 X) }, k
    15. - (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类里面增加两个方法
      1. - (CGSize)attachmentInfoViewContentSize:(NIMMessageModel *)messageModel cellWidth:(CGFloat)width;6 H# g9 \' A$ Z
      2. - (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/
    使用道具 举报 回复
    严禁恶意灌水!!!拒绝伸手党!!!
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    ض