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の文字が変わった時に発火 | × |
最後に
ここには書かなかったけど他にも位置情報の表示や画像の表示、送信ボタンをカスタマイズしたりボタンを追加したりも可能で便利。