I need a custom "notification" cell like this:

Some tips to help me working around in this idea?
I'm thinking to create a new NotificationCell class that will be child of UICollectionViewCell and then create NotificationsSizeCalculator, NotificationsCollectionViewFlowLayout and NotificationsCollectionViewLayoutAttributes
Is that a good approach?
Are you interested in that kind of feature?
Thank you in advance!
Ok, I saw in other issues that the solution is to do this customization under .custom case.
Any tips about implementing a new custom cell?
I got this to work by doing the following. Seems to basically be what you suggested.
Reference the project's example for the rest of ConversationViewController. This example renders a red block for your custom message.
import UIKit
import MessageKit
internal class ConversationViewController: MessagesViewController {
override func viewDidLoad() {
messagesCollectionView = MessagesCollectionView(frame: .zero, collectionViewLayout: MyCustomMessagesFlowLayout())
messagesCollectionView.register(MyCustomCell.self)
super.viewDidLoad()
//...
}
//...
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(MyCustomCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
return cell
}
return super.collectionView(collectionView, cellForItemAt: indexPath)
}
}
// Customize this collection view cell with data passed in from message, which is of type .custom
open class MyCustomCell: UICollectionViewCell {
open func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
self.contentView.backgroundColor = UIColor.red
}
}
import Foundation
import MessageKit
open class MyCustomMessagesFlowLayout: MessagesCollectionViewFlowLayout {
lazy open var customMessageSizeCalculator = CustomMessageSizeCalculator(layout: self)
override open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
if case .custom = message.kind {
return customMessageSizeCalculator
}
return super.cellSizeCalculatorForItem(at: indexPath);
}
}
open class CustomMessageSizeCalculator: MessageSizeCalculator {
open override func messageContainerSize(for message: MessageType) -> CGSize {
//TODO - Customize to size your content appropriately. This just returns a constant size.
return CGSize(width: 300, height: 130)
}
}
@wildseansy This is an awesome example! It's exactly what's expected to create a custom cell 馃槃
馃憦 馃憦 馃憦
That is what I was looking for! Thank you so much @wildseansy 馃榾
@wildseansy, thank you for your solution, it's been very helpful to me. One final part I am stuck is on how I can place the custom cell on the right or the left based on who has sent the message. I thought the following would work but alas it does not have the desired effect:
class CustomMessageSizeCalculator: MessageSizeCalculator {
override init(layout: MessagesCollectionViewFlowLayout?) {
super.init(layout: layout)
self.incomingMessagePadding = UIEdgeInsets(top: 0, left: 4, bottom: 0, right: UIScreen.main.bounds.width - 294)
self.outgoingMessagePadding = UIEdgeInsets(top: 0, left: UIScreen.main.bounds.width - 294, bottom: 0, right: 4)
}
override func sizeForItem(at indexPath: IndexPath) -> CGSize {
return CGSize(width: 290, height: 194)
}
}
@fr-josh - it might be because you're overriding sizeForItem, self.incomingMessagePadding/self.outgoingMessagePadding won't be used properly unless you call super.sizeForItem, or use these values in your computation. See the superclass for more context. Looks like you might want to use messagesLayout.itemWidth for your width.
@wildseansy Do you think you'd be up for the task of documenting your answer above in Documentation/FAQs.md? It would be a huge help to our project
@SD10 - sure no prob. Can submit sometime today/tomorrow
@wildseansy No rush, at your own pace 馃憤
Is there any way to load custom cell from .xib?馃
Found this workaround for my question:
import UIKit
import MessageKit
import SnapKit
class CustomChatMessageCell: UICollectionViewCell, BaseCellProtocol {
func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
let customContentView = CutomMessageContentView.instantiateFromNib()!
self.contentView.addSubview(customContentView)
customContentView.snp.makeConstraints { make in
make.top.bottom.leading.trailing.equalTo(customContentView.superview!)
}
}
}
I will just leave this here as it gave me a pretty big headache while implementing my subclass of MessageContentCell (I used this parent class instead of UICollectionViewCell like in the example code above because I still wanted to use all the extra features like top and bottom label, sizing and positioning for my custom cell). Maybe it is wise to add it to the FAQ too?
You are supposed to add your custom content view (in my case a LinkPreviewView) to the messageContainerView of your subclass of MessageContentCell so that all elements are positioned and sized correctly. However, MessageContainerView is actually a subclass of UIImageView, which has user interaction disabled per default! So if you add any textviews with hyperlinks, buttons or other interactable stuff you need to enable user interaction on the MessageContainerView in order for it to work properly.
Here is an example on how to do that (not the complete code for my subclass):
class LinkPreviewCollectionViewCell: MessageContentCell {
open class func reuseIdentifier() -> String { return "messagekit.cell.linkPreview" }
lazy open var linkPreviewView: LinkPreviewParentView = {
return LinkPreviewParentView()
}()
open override func setupSubviews() {
super.setupSubviews()
self.messageContainerView.addSubview(linkPreviewView)
// We need to enable user interaction on the MessageContainerView, since it is a UIImageView subclass, which has user interaction disabled per default
self.messageContainerView.isUserInteractionEnabled = true
self.setupConstraints()
}
}
This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
This issue has been auto-closed because there hasn't been any activity for at least 21 days. However, we really appreciate your contribution, so thank you for that! 馃檹 Also, feel free to open a new issue if you still experience this problem 馃憤.
it's not working for me how ?!
I went with @Luke47 method for creating a custom cell by subclassing MessageContentCell. So that I could still use those extra features like top and bottom label, sizing and positioning and the avatar view. When displaying my custom cell everything is correctly positioned but MesssageDataSource delegate only calls methods like "ConfigureAvatarView", and "cellTopLabelAttributedText" for the non custom cells. Yet "cellTopLabelHeight" and "messageForItem" is called everytime even for custom cells. Id like to use all of the features of MessageDatSource to be able to add timestamps to those custom cells, If you guys could point me in the right direction it would be much appreciated. Also, I did notice that within my subclass of MessageContentCell you can access there avatar view and labels, I would rather use the MessageDataSource Delegate to populate those fields though.
This documentation hasn't still been added to the FAQs since May
Have you looked at the example project? I have an advanced example that shows this and more.
Sent with GitHawk
@tobitech see here. Agree it might be worth pointing to this example from the FAQ tho
Okay i've see that. What if I want to have more than one custom cells (say for Audio Message, Document Message, Contact Message), would i create CustomFlowLayouts for each of them and register different cells for each of them?
@tobitech - You can just create one CustomFlowLayout.
You would need to inspect the .custom(Any?) parameter that is stored in the .custom struct type. Using this internal data of type Any, you can then parse out whether it's an audio, document, or contact message, and then determine what height/width to supply to the flow layout.
Alternatively, you can also extend your message model to be a little more specific for this custom case. This is how I implemented my custom cells, so it's a little clearer when something goes wrong:
/* MODELS */
internal enum ChatMessageSubtype {
case none()
case audio()
case document(CGFloat)
case contact()
}
internal struct MyChatMessage: MessageType {
var messageId: String
var sender: Sender
var sentDate: Date
var kind: MessageKind
var subtype: ChatMessageSubtype
private init(kind: MessageKind, sender: Sender, messageId: String, date: Date) {
self.kind = kind
self.subtype = .none()
self.sender = sender
self.messageId = messageId
self.sentDate = date
}
/*
You would initialize a custom message like so:
MyChatMessage(kind: .custom(nil), subtype: .audio(), sender: senderObject, messageId: "<messageID>", date: Date())
*/
init(kind: MessageKind, subtype: ChatMessageSubtype, sender: Sender, messageId: String, date: Date) {
self.init(kind: kind, sender: sender, messageId: messageId, date: date)
self.subtype = subtype
}
init(text: String, sender: Sender, messageId: String, date: Date) {
self.init(kind: .text(text), sender: sender, messageId: messageId, date: date)
}
//...See MockMessage.swift for the rest of the model.
}
/* Flow layout */
open class CustomMessagesFlowLayout: MessagesCollectionViewFlowLayout {
lazy open var customCellCalculator = CustomCellCalculator(layout: self)
override open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
if case .custom = message.kind {
return customCellCalculator
}
return super.cellSizeCalculatorForItem(at: indexPath);
}
}
open class CustomCellCalculator: MessageSizeCalculator {
open override func messageContainerSize(for message: MessageType) -> CGSize {
let maxWidth = messageContainerMaxWidth(for: message)
let customMessage = message as! MyChatMessage
var height:CGFloat = 130.0
switch customMessage.subtype {
case .audio():
height = 50.0
break
case .document(let documentHeight):
height = documentHeight
case .contact():
height = 60.0
default: break
}
return CGSize(width: maxWidth, height: height)
}
}
Thanks would try it out
pod 'MessageKit', '~> 2.0.0-beta.1'
Incoming and Outgoing messages padding issue still exists in Custom messages
There is no prominent Answer from anyone
Either Incoming or Outgoing message, Both showed in the middle of the screen
even after implementing the padding as people suggested
And there is no Audio message option like WhatsApp which has high precedence
I will be thankful if anyone will help me :-)
you can do like this, add your view to messageContainerView
import MessageKit
import SnapKit
open class MyMessageCell: MessageContentCell {
let myView = MyView()
open override func setupSubviews() {
super.setupSubviews()
messageContainerView.addSubview(myView)
myView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
super.configure(with: message, at: indexPath, and: messagesCollectionView)
// do something with `myView`
}
}
open class MyViewSizeCalculator: MessageSizeCalculator {
public override init(layout: MessagesCollectionViewFlowLayout? = nil) {
super.init()
self.layout = layout
}
/// don't override this function
open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
// do nothing
return super.sizeForItem(at: indexPath)
}
/// override this function
open override func messageContainerSize(for message: MessageType) -> CGSize {
/// ur custom view size
return CGSize(width: 200, height: 100)
}
}
@umair2ooo Audio messages were added in 3.0
Sent with GitHawk
is there a way to tap on the "milling call" button?
I have an issue like this, have a look here: https://github.com/MessageKit/MessageKit/issues/1227
Most helpful comment
I got this to work by doing the following. Seems to basically be what you suggested.
Reference the project's example for the rest of
ConversationViewController. This example renders a red block for your custom message.ConversationViewController.swift
MyCustomCell.swift
MyCustomMessagesFlowLayout.swift