入职新公司,是一家做社交产品的,刚到时候已经完成了部分功能,上个开发人员采用的是storyboard进行界面搭建,对于后期维护,可想而知,费劲。
为了节省开发周期,即时通讯采用的是融云的IMKit,可偷懒一时爽,后台的改版,让我变得心累。
IMKit是融云为了帮用户搭的聊天框架,节省开发周期的同时,却也限制界面的可扩展性。
框架没选好,开发一直爽(爽到爆,爽到让你哭)。
一次次修改,一次次出现问题,IMKit让我想哭。
在改版了3次之后,决定彻底放弃IMKit,采用IMLib,所有的界面自己来做。而且融云IMKit的UX根本无法满足我们的需要,作为社交产品,对于用户体验要求是相当高,体验不好,对产品来说,这是致命问题。
最终决定采用老外写的一个即时聊天框架MessageKit。不得不说,人家是牛逼的。
GitHub地址:https://github.com/MessageKit/MessageKit
聊天列表采用的是UICollectionView,对常用聊天功能也进行了封装,支持文字,图片,语音,视频等。开发过程中,只许替换自己的内容即可。
一、布局:
所有的界面都是围绕着控制器MessagesViewController进行,界面采用了一个UICollectionView用于展示聊天信息,在底部是一个封装的聊天输入框InputBarAccessoryView,在控制器中实现了对键盘监听,用于修改界面的位置。
/// The `MessagesCollectionView` managed by the messages view controller object.
open var messagesCollectionView = MessagesCollectionView()
/// The `InputBarAccessoryView` used as the `inputAccessoryView` in the view controller.
open var messageInputBar = InputBarAccessoryView()
所有的cell继承MessageContentCell或MessageCollectionViewCell
MessageContentCell是在MessageCollectionViewCell基础上做了一些聊天中常用的封装,比如:头像、昵称、消息内容已经做好了布局,只需要填充内容即可。
MessageCollectionViewCell是继承自UICollectionViewCell这就需要有开发人员自己完成消息的界面布局了。
动态Cell的高度,都继承CellSizeCalculator类,在该类中已经提供了一些super 方法,
/// The layout object for which the cell size calculator is used.
public weak var layout: UICollectionViewFlowLayout?
/// Used to configure the layout attributes for a given cell.
///
/// - Parameters:
/// - attributes: The attributes of the cell.
/// The default does nothing
open func configure(attributes: UICollectionViewLayoutAttributes) {}
/// Used to size an item at a given `IndexPath`.
///
/// - Parameters:
/// - indexPath: The `IndexPath` of the item to be displayed.
/// The default return .zero
open func sizeForItem(at indexPath: IndexPath) -> CGSize { return .zero }
所有子类的高度Calculator都可以在此基础上进行override。如下:
open override func configure(attributes: UICollectionViewLayoutAttributes) {
super.configure(attributes: attributes)
guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
let dataSource = messagesLayout.messagesDataSource
let indexPath = attributes.indexPath
let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
attributes.messageLabelInsets = messageLabelInsets(for: message)
attributes.messageLabelFont = messageLabelFont
switch message.kind {
case .attributedText(let text):
guard !text.string.isEmpty else { return }
guard let font = text.attribute(.font, at: 0, effectiveRange: nil) as? UIFont else { return }
attributes.messageLabelFont = font
default:
break
}
}
二、消息内容
所有的传值,都是通过delegate来实现的,
//cell的点击响应
func didPauseAudio(in cell: AudioMessageCell)
func didStartAudio(in cell: AudioMessageCell)
//cell的数据源
func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType
func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
使用MessageKit能有效帮助快速搭建聊天界面。