入职新公司,是一家做社交产品的,刚到时候已经完成了部分功能,上个开发人员采用的是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能有效帮助快速搭建聊天界面。