お世話になっております。iOSアプリのswiftのコードについて質問がございます。
MessageKitというチャットを再現できるライブラリを用いてチャット風の画面を実装しています。
基本的なレイアウトや文言の表示をするところまでは実装できたのですが、企業のLINEでたまに見るメッセージの中にボタンやリンク付きの文言を埋め込む方法がわからず悩んでおります。
イメージとしては以下のような感じです。
・吹き出しの中に「はい」「いいえ」のようなボタンを表示し、押下するとその返答に即したメッセージを送信
・吹き出しの中に「ここをタップ」というリンク付きの文言が表示され、押下すると外部サイトへ飛ぶことができる
以下は現在のコードとなります。
ChatViewControllerのcreateMeMessageとcreateOtherMessageで基本のチャットの文言を作成しているのですが、
リンクやボタン埋め込みのために新しくcreateChoiseMessageを作成したところうまくいっていないといった状況です…。
ChatViewController
1import MessageKit 2import UIKit 3 4class ChatViewController: MessagesViewController { 5 6 private var messages: [MockMessage] = [] 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 11 DispatchQueue.main.async { 12 self.messages = self.getMyMessages() + self.getOtherMessages() 13 self.messagesCollectionView.reloadData() 14 self.messagesCollectionView.scrollToBottom() 15 } 16 17 messagesCollectionView.messagesDataSource = self 18 messagesCollectionView.messageCellDelegate = self 19 messagesCollectionView.messagesLayoutDelegate = self 20 messagesCollectionView.messagesDisplayDelegate = self 21 messagesCollectionView.messageCellDelegate = self 22 } 23 24 func getMeMessages() -> [MockMessage] { 25 return [ 26 createMessage(text: "あ"), 27 createMessage(text: "い"), 28 createMessage(text: "う"), 29 ] 30 } 31 32 func getOtherMessages() -> [MockMessage] { 33 return [ 34 createOtherMessage(text: "え"), 35 createOtherMessage(text: "お"), 36 createChoiseMessage(text: "猫が好き", yesText: "はい", noText: "いいえ"), 37 ] 38 } 39 40 func createMessage(text: String) -> MockMessage { 41 let attributedText = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: 15), 42 .foregroundColor: UIColor.black]) 43 return MockMessage(attributedText: attributedText, sender: currentSender(), messageId: UUID().uuidString, date: Date()) 44 } 45 46 func createOtherMessage(text: String) -> MockMessage { 47 let attributedText = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: 15), 48 .foregroundColor: UIColor.black]) 49 return MockMessage(attributedText: attributedText, sender: otherSender(), messageId: UUID().uuidString, date: Date()) 50 } 51 52 func createChoiseMessage(text: String, yesText: String, noText: String) -> MockMessage { 53 let text = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: 15), 54 .foregroundColor: UIColor.blue]) 55 let attributedText1 = NSAttributedString(string: yesText, attributes: [.font: UIFont.systemFont(ofSize: 30), 56 .foregroundColor: UIColor.blue]) 57 let attributedText2 = NSAttributedString(string: noText, attributes: [.font: UIFont.systemFont(ofSize: 30), 58 .foregroundColor: UIColor.red]) 59 return MockMessage(text: text, yesText: yesText, noText: noText, 60 sender: otherSender(), messageId: UUID().uuidString, date: Date()) 61 } 62 63 override func didReceiveMemoryWarning() { 64 super.didReceiveMemoryWarning() 65 } 66} 67 68extension ChatViewController: MessagesDataSource { 69 70 // idとdisplayNameをプロパティに持つ構造体Senderを返す 71 func currentSender() -> SenderType { 72 return Sender(id: "1", displayName: "me") 73 } 74 75 // idとdisplayNameをプロパティに持つ構造体Senderを返す 76 func otherSender() -> SenderType { 77 return Sender(id: "2", displayName: "other") 78 } 79 80 func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { 81 return messages.count 82 } 83 84 func messageForItem(at indexPath: IndexPath, 85 in messagesCollectionView: MessagesCollectionView) -> MessageType { 86 87 return messages[indexPath.section] 88 } 89 90 func cellTopLabelAttributedText(for message: MessageType, 91 at indexPath: IndexPath) -> NSAttributedString? { 92 93 let name = message.sender.displayName 94 return NSAttributedString( 95 string: name, 96 attributes: [ 97 .font: UIFont.preferredFont(forTextStyle: .caption1), 98 .foregroundColor: UIColor(white: 0.3, alpha: 1) 99 ] 100 ) 101 } 102 103 // URLから画像をセットする場合 104 func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { 105 let avatar: Avatar 106 if let url = URL(string: messages[indexPath.section].userImagePath) { 107 do { 108 let imageData = try Data(contentsOf: url) 109 let image = UIImage(data: imageData) 110 avatar = Avatar(image: image, initials: "?") 111 } catch { 112 avatar = Avatar(image: nil, initials: "?") 113 } 114 } else { 115 avatar = Avatar(image: nil, initials: "?") 116 } 117 avatarView.set(avatar: avatar) 118 } 119 120 func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] { 121 return [.url, .address, .phoneNumber, .date, .transitInformation] 122 } 123} 124 125・ 126・ 127・ 128 129extension ChatViewController: MessageCellDelegate { 130 131 func didTapAvatar(in cell: MessageCollectionViewCell) { 132 print("Avatar tapped") 133 } 134 135 func didTapMessage(in cell: MessageCollectionViewCell) { 136 print("Message tapped") 137 } 138 139} 140 141extension ChatViewController: MessageLabelDelegate { 142 func didSelectAddress(_ addressComponents: [String: String]) { 143 print("Address Selected: (addressComponents)") 144 } 145 146 func didSelectPhoneNumber(_ phoneNumber: String) { 147 print("Phone Number Selected: (phoneNumber)") 148 } 149 150 func didSelectURL(_ url: URL) { 151 print("URL Selected: (url)") 152 } 153 154} 155
MockMessage
1import MessageKit 2import UIKit 3 4internal struct MockMessage: MessageType { 5 6 var sender: SenderType 7 var messageId: String 8 var sentDate: Date 9 var kind: MessageKind 10 var yesText: NSAttributedString? 11 var noText: NSAttributedString? 12 var userImagePath: String 13 14 private init(kind: MessageKind, yesText: NSAttributedString? = nil, noText: NSAttributedString? = nil, sender: SenderType, messageId: String, date: Date, userImagePath: String? = nil) { 15 self.kind = kind 16 self.sender = sender 17 self.messageId = messageId 18 self.sentDate = date 19 self.userImagePath = userImagePath ?? "" 20 self.yesText = yesText 21 self.noText = noText 22 } 23 24 init(attributedText: NSAttributedString, sender: SenderType, messageId: String, date: Date) { 25 self.init(kind: .attributedText(attributedText), sender: sender, messageId: messageId, date: date) 26 } 27 28 init(text: String, yesText: NSAttributedString, noText: NSAttributedString, sender: SenderType, messageId: String, date: Date) { 29 self.init(kind: .text(text), yesText: yesText, noText: noText, sender: sender, messageId: messageId, date: date) 30 } 31} 32
MessageKind
1import Foundation 2 3public enum MessageKind { 4 5 case text(String) 6 7 /// A message with attributed text. 8 case attributedText(NSAttributedString) 9 10 /// A photo message. 11 case photo(MediaItem) 12 13 /// A video message. 14 case video(MediaItem) 15 16 /// A location message. 17 case location(LocationItem) 18 19 /// An emoji message. 20 case emoji(String) 21 22 /// An audio message. 23 case audio(AudioItem) 24 25 /// A contact message. 26 case contact(ContactItem) 27 28 /// A link preview message. 29 case linkPreview(LinkItem) 30 31 /// A custom message. 32 /// - Note: Using this case requires that you implement the following methods and handle this case: 33 /// - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell 34 /// - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator 35 case custom(Any?) 36 37 // MARK: - Not supported yet 38 39// case system(String) 40// 41// case placeholder 42 43}
使用させていただいているライブラリ
https://github.com/MessageKit/MessageKit
参考にさせていただいたサイト
https://qiita.com/shoboo/items/bb3dd56a696c46054297
https://messagekit.github.io/index.html
バージョンなど
MessageKit (3.7.0)
x86_64-apple-darwin20.5.0
もしよろしければご教示いただけますと幸いです、何卒よろしくお願いいたします。
あなたの回答
tips
プレビュー