見出し画像

iOSの MessageKit による画像送信UIの作成

iOSの「MessageKit」による画像送信UIの作成を試したので、まとめました。

・Xcode 14
・iOS 16

前回

1. コードの編集

前回のViewControllerのコードを編集して、画像送信UIを追加します。

(1) メディア (ChatMedia) の追加。
「MediaItem」を継承した画像情報を保持する構造体です。

// メディア
struct ChatMedia: MediaItem {
    var url: URL?
    var image: UIImage?

    // プレースホルダー画像の取得
    var placeholderImage: UIImage {
        return UIImage()
    }

    // サイズの取得
    var size: CGSize {
        return CGSize(width: UIScreen.main.bounds.width/2, height: UIScreen.main.bounds.width/2)
    }

    // URLによるメディアの生成
    static func new(url: URL?) -> ChatMedia {
        ChatMedia(url: url, image: nil)
    }

    // 画像によるメディアの生成
    static func new(image: UIImage?) -> ChatMedia {
        ChatMedia(url: nil, image: image)
    }
}

(2) メッセージ種別 (MessageKindType) の追加。
テキストメッセージと画像メッセージのどちらであるかを示す列挙型です。

// メッセージ種別
enum MessageKindType {
    case text(message: String)
    case image(mediaItem: ChatMedia)
}

(3) メッセージ (ChatMessage) をテキストと画像の両対応に変更。

// メッセージ
struct ChatMessage: MessageType {
    var sender: SenderType  // 送信者
    var messageId: String  // メッセージID
    var sentDate: Date  // 送信日時
    var kindType: MessageKindType // 追加

    // メッセージ種別
    var kind: MessageKind {
        switch kindType {
        case .text(let message):
            return .attributedText(NSAttributedString(
                string: message,
                attributes: [
                .font: UIFont.systemFont(ofSize: 14.0),
                .foregroundColor: sender.senderId == "0" ? UIColor.white : UIColor.label
            ]))
        case .image(let mediaItem):
            return .photo(mediaItem)
        }
    }

    // テキストメッセージの生成
    static func new(sender: SenderType, message: String) -> ChatMessage {
        return ChatMessage(
            sender: sender,
            messageId: UUID().uuidString,
            sentDate: Date(),
            kindType: .text(message: message))
    }

    // 画像メッセージの生成
    static func new(sender: SenderType, image: UIImage) -> ChatMessage {
        return ChatMessage(
            sender: sender,
            messageId: UUID().uuidString,
            sentDate: Date(),
            kindType: .image(mediaItem: ChatMedia.new(image: image)))
    }
}

(4) ViewControllerに写真ピッカー (picker) を追加。
「PhotosUI」のインポートとデリゲートも追加します。

import PhotosUI
// ViewController
final class ViewController: MessagesViewController {
            :        
    // 写真ピッカー
    private lazy var picker: PHPickerViewController = {
        var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
        configuration.filter = .images
        configuration.selectionLimit = 1
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        return picker
    }()
            :        
}
// PHPickerViewControllerDelegate
extension ViewController: PHPickerViewControllerDelegate {
    // 写真ピッカーで写真選択時に呼ばれる
    func picker(_ picker: PHPickerViewController,
        didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true, completion: nil)
        results.forEach { result in
            result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] item, error in
                if let error = error {
                    debugPrint(error.localizedDescription)
                } else if let image = item as? UIImage {
                    // 画像メッセージの追加
                    DispatchQueue.main.async {
                        let entity = ChatMessage.new(sender: ChatSender.me, image: image)
                        self?.messageList.append(entity)
                    }
                }
            }
        }
    }
}

(5) messageInputBarにクリップボタンの追加。
押下時に写真ピッカーを開きます。

    // ビューロード時に呼ばれる
    override func viewDidLoad() {
        super.viewDidLoad()
            :        
        // クリップボタンの追加
        let clipBarButtonItem = InputBarButtonItem()
        clipBarButtonItem.image = UIImage(systemName: "paperclip")
        clipBarButtonItem.setSize(CGSize(width: 24.0, height: 36.0), animated: false)
        clipBarButtonItem.onTouchUpInside { _ in
            self.present(self.picker, animated: true, completion: nil)
        }
        messageInputBar.setStackViewItems([clipBarButtonItem, .flexibleSpace], forStack: .left, animated: false)
        messageInputBar.setLeftStackViewWidthConstant(to: 36.0, animated: false)
    }

2. 実行

実行すると、以下のようにクリップボタンから画像メッセージを送信できます。





この記事が気に入ったらサポートをしてみませんか?