I am struggling on how to display a system message in a chatroom. Currently, I have already built the chatroom using MessageKit in Swift and finished the overall UI. What I want is, when I click the red button at the upper right corner, a system message "The button is tapped" will automatically display in the chatroom, like the sample picture below. Thanks a lot if anyone can help!
Asked
Active
Viewed 459 times
1 Answers
0
This answer may be a bit late but the solution is quite simple. All you need to do is create a custom cell and configure it with the messages view controller data source.
There's a comprehensive guide you can follow on the official repo for help with what to do alongside an example
Here's some demo code (you won't be able to copy and paste this since I'm referencing some custom UIView subclasses)
Firstly, create your UICollectionViewCell
class SystemMessageCell: CollectionCell<MessageType> {
lazy var messageText = Label()
.variant(.regular(.small))
.color(.gray)
.align(.center)
override func setupView() {
addSubview(messageText)
}
override func setupConstraints() {
messageText.snp.makeConstraints { $0.edges.equalToSuperview() }
}
override func update() {
guard let item = item else { return }
switch item.kind {
case .custom(let kind):
guard let kind = kind as? ChatMessageViewModel.Kind else { return }
switch kind {
case .system(let systemMessage):
messageText.text = systemMessage
}
default:
break
}
}
}
Secondly, you need to create two separate files. One is a size calculator and the other is a custom flow layout.
class SystemMessageSizeCalculator: MessageSizeCalculator {
override func messageContainerSize(for message: MessageType) -> CGSize {
// Just return a fixed height.
return CGSize(width: UIScreen.main.bounds.width, height: 20)
}
}
class SystemMessageFlowLayout: MessagesCollectionViewFlowLayout {
lazy open var sizeCalculator = SystemMessageSizeCalculator(layout: self)
override open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
if case .custom = message.kind {
return sizeCalculator
}
return super.cellSizeCalculatorForItem(at: indexPath);
}
}
Finally, hook it all up in your MessagesViewController like so:
class ChatViewController: MessagesViewController {
override func viewDidLoad() {
messagesCollectionView = MessagesCollectionView(frame: .zero, collectionViewLayout: SystemMessageFlowLayout())
super.viewDidLoad()
messagesCollectionView.register(SystemMessageCell.self)
}
// MARK: - Custom Cell
override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
fatalError("Ouch. nil data source for messages")
}
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
if case .custom = message.kind {
let cell = messagesCollectionView.dequeueReusableCell(SystemMessageCell.self, for: indexPath)
cell.item = message
return cell
}
return super.collectionView(collectionView, cellForItemAt: indexPath)
}
}
The end result will be something like this:

Jesse Onolemen
- 1,277
- 1
- 15
- 32
-
I have a question ???. I want to add an attribute string to .custom(). It's ok ???? – Nguyễn Quang Tuấn Jul 20 '21 at 19:31