1

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!

sample picture

Kevin
  • 23
  • 3

1 Answers1

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:

Sample screenshot

Jesse Onolemen
  • 1,277
  • 1
  • 15
  • 32