Edited at

Message Kitの使い方まとめ

More than 1 year has passed since last update.

iosでチャット画面を作る際、JSQMessagesViewControllerがdeprecatedになって絶望していた。

そんな中、ついにMessageKitのver1.0.0が出たが、ドキュメントなし。毎回コードとにらめっこして実装するのは地獄なので軽くメモ。


環境


  • macOS High Sierra 10.13.4

  • Xcode 9.4

  • iOS 11.4

  • Swift 4.1

  • MessageKit 1.0.0


導入

carthageやcocoaPod使って頑張ってください。


メッセージオブジェクトの作成

まずはこんな感じでメッセージオブジェクトを作成。必須の要素以外にも欲しい変数を定義できるので便利。

struct Message: MessageType {

/// 必須
var messageId: String
var sender: Sender
var sentDate: Date
var kind: MessageKind

/// 必須ではない
var userImagePath: String
}


ViewControllerの作成

MessagesViewControllerを継承したViewControllerを作るだけでok。部分的にチャット画面を使いたいよーって場合はcontainerView使えば対応可能できないみたい( cf https://github.com/MessageKit/MessageKit/issues/737 )。そして、delegateなどをセット。

class ChatViewController: MessagesViewController {

var messages: [Message] = []

override func viewDidLoad() {
super.viewDidLoad()

messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self
messagesCollectionView.messageCellDelegate = self
messageInputBar.delegate = self
}
}


protocolの実装

さて、ここからが少し面倒なところ。それぞれの関数を説明していきます。よく使うであろうものだけサンプルコード載せておきます。


MessagesDataSource

関数名
機能
必須かどうか

currentSender
自分の情報を設定

numberOfSections
表示するメッセージの数

messageForItem
メッセージの実態。返り値はMessageType

cellTopLabelAttributedText
セルの上の文字
×

messageTopLabelAttributedText
メッセージの上の文字
×

messageBottomLabelAttributedText
メッセージの下の文字
×

extension ChatViewController: MessagesDataSource {

func currentSender() -> Sender {
return Sender(id: "12345", displayName: "taro")
}

func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int {
return messages.count
}

func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
return messages[indexPath.section]
}
}


MessagesLayoutDelegate

関数名
機能
必須かどうか

headerViewSize
HeaderのView Size
×

footerViewSize
FooterのView Size
×

cellTopLabelHeight
cellTopLabelAttributedTextを表示する高さ
×

messageTopLabelHeight
messageTopLabelAttributedTextを表示する高さ
×

messageBottomLabelHeight
messageBottomLabelAttributedTextを表示する高さ
×


MessagesDisplayDelegate

(*は後で詳しく説明)

関数名
機能
必須かどうか

messageStyle
messageの背景スタイル、角丸とか三角のちょぼ付けるとかを指定
×

backgroundColor
背景色
×

messageHeaderView
Header View
×

messageFooterView
Footer View
×

configureAvatarView*
Avatar View
×

以下はtextの場合専用

textColor
テキストの色
×

enabledDetectors*
自動検出してくれるものを指定
×

detectorAttributes
自動検出されたもののAttributes
×

extension ChatViewController: MessagesDataSource {

/// URLから画像をセットする場合はこのようにする。非同期にできないのが辛いところ
func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
let avatar: Avatar
if let url = URL(string: messages[indexPath.section].userImagePath) {
do {
let imageData = try Data(contentsOf: url)
let image = UIImage(data: imageData)
avatar = Avatar(image: image, initials: "?")
} catch {
avatar = Avatar(image: nil, initials: "?")
}
} else {
avatar = Avatar(image: nil, initials: "?")
}
avatarView.set(avatar: avatar)
}

/// こうしておけば、自動で電話番号やURLを検出してくれる。
/// もちろんタップ処理も実装されている
func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] {
return [.url, .address, .phoneNumber, .date, .transitInformation]
}
}


MessageCellDelegate

tap系はシンプル書くほどでもないので省略。MessageLabelDelegate を継承しているのでdetectorsのタップ処理もこの中に含まれている。


MessageInputBarDelegate

関数名
機能
必須かどうか

messageInputBar(_:didPressSendButtonWith:)
送信ボタンが押された時
×

messageInputBar(_:didChangeIntrinsicContentTo:)
TextViewのサイズが変わった時に発火
×

messageInputBar(_:textViewTextDidChangeTo:)
TextViewの文字が変わった時に発火
×


最後に

ここには書かなかったけど他にも位置情報の表示や画像の表示、送信ボタンをカスタマイズしたりボタンを追加したりも可能で便利。