0%

MessageKit源码分析

MessageKit是一个开源的IM 消息聊天UI框架。

MessageKit采用UICollectionView而非UITableView作为主体架构(为什么要这么设计Why?),采用UICollectionViewCell实现聊天cell。一个section对应一条聊天消息,默认一个section里面只有一个cell(为什么要这么设计Why?)。

作为一个框架,难就难在如何封装各种风格迥异的聊天cell?MessageKit自定义了一种CollectionView布局方式MessagesCollectionViewFlowLayout,它继承自UICollectionViewFlowLayout。对应需要自定义layoutAttributes—MessagesCollectionViewLayoutAttributes,继承自UICollectionViewLayoutAttributes。

框架内部提供了几种默认的消息类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/// An enum representing the kind of message and its underlying kind.
public enum MessageKind {

/// A standard text message.
///
/// - Note: The font used for this message will be the value of the
/// `messageLabelFont` property in the `MessagesCollectionViewFlowLayout` object.
///
/// Using `MessageKind.attributedText(NSAttributedString)` doesn't require you
/// to set this property and results in higher performance.
case text(String)

/// A message with attributed text.
case attributedText(NSAttributedString)

/// A photo message.
case photo(MediaItem)

/// A video message.
case video(MediaItem)

/// A location message.
case location(LocationItem)

/// An emoji message.
case emoji(String)

/// An audio message.
case audio(AudioItem)

/// A contact message.
case contact(ContactItem)

/// A link preview message.
case linkPreview(LinkItem)

/// A custom message.
/// - Note: Using this case requires that you implement the following methods and handle this case:
/// - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
/// - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
case custom(Any?)

// MARK: - Not supported yet

// case system(String)
//
// case placeholder

}

每种消息类型提供了默认的cell样式,如果不想用默认的样式可以通过代理自己返回。每种cell对应一种CellSizeCalculator,用于提供cell的宽高。内部提供的比如:TextMessageCell—TextMessageSizeCalculator、MediaMessageCell—MediaMessageSizeCalculator、AudioMessageCell—AudioMessageSizeCalculator。

MessageKit的设计思想真的吊,框架提供了默认样式,如果不想用默认的样式可以通过代理自己返回。

几种基类

MessagesViewController—>UIViewController

实际使用时可以继承MessagesViewController或拷贝其源码到自己的控制器。

MessagesCollectionView—>UICollectionView

xxx—>MessageContentCell—>MessageCollectionViewCell—>UICollectionViewCell

MessageContentCell里已经添加了很多必要的控件,比如:avatarView、messageContainerView、cellTopLabel等等。

xxx—>MessageSizeCalculator—>CellSizeCalculator

Calculator负责配置LayoutAttributes,并计算cell的size。MessageSizeCalculator内部已经帮你计算好了,子控件的高度由外部代理。

MessagesCollectionViewFlowLayout—>UICollectionViewFlowLayout

MessagesCollectionViewFlowLayout负责返回cell的size,实际的size计算由cell对应的Calculator完成。由于cell的种类繁多,Layout内部已经内置了各种Calculator,也可以由外部传入(代理)。

MessagesCollectionViewLayoutAttributes—>UICollectionViewLayoutAttributes

MessagesCollectionView

内部已经注册了几种默认的样式cell:

1
2
3
4
5
6
7
8
9
10
11
12
// MARK: - Methods
private func registerReusableViews() {
register(TextMessageCell.self)
register(MediaMessageCell.self)
register(LocationMessageCell.self)
register(AudioMessageCell.self)
register(ContactMessageCell.self)
register(TypingIndicatorCell.self)
register(LinkPreviewMessageCell.self)
register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader)
register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter)
}

默认cell样式

1
https://raw.githubusercontent.com/MessageKit/MessageKit/master/Assets/CellStructure.png

自定义cell样式

虽然框架已经提供了很多种cell样式了,但是UI是最容易变的。所以还是需要完全自定义cell样式。

觉得文章有帮助可以打赏一下哦!