Use this file to discover all available pages before exploring further.
A MessageTemplate defines and customizes both the structure and the behavior of the MessageBubble. It acts as a schema for creating MessageBubble components, allowing you to manage the appearance and interactions of message bubbles within your application.
What this does: Retrieves all registered message templates from the UI Kit data source, giving you the full list of templates to modify or extend.
Find the template for the message type you want to customize (e.g., text messages):
Kotlin
Java
for (template in messageTemplates) { if (template.type == UIKitConstants.MessageType.TEXT) { // Code to customize text message template }}
for(CometChatMessageTemplate template : messageTemplates){ if(template.getType().equals(UIKitConstants.MessageType.TEXT)){ // Code to customize text message template }}
What this does: Iterates through the templates list and matches the template whose type equals UIKitConstants.MessageType.TEXT, so you can customize only text message bubbles.
Customize a view on the matched template (e.g., set a custom content view):
Kotlin
Java
template.setContentView(object : MessagesViewHolderListener() { override fun createView( context: Context, cometChatMessageBubble: CometChatMessageBubble, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment ): View { return LayoutInflater.from(context).inflate(R.layout.your_custom_layout, null) } override fun bindView( context: Context, view: View, baseMessage: BaseMessage, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment, viewHolder: RecyclerView.ViewHolder, list: List<BaseMessage>, i: Int ) { // Bind your custom view data here }})
template.setContentView(new MessagesViewHolderListener() { @Override public View createView(Context context, CometChatMessageBubble messageBubble, UIKitConstants.MessageBubbleAlignment alignment) { return LayoutInflater.from(context).inflate(R.layout.your_custom_layout, null); } @Override public void bindView(Context context, View createdView, BaseMessage message, UIKitConstants.MessageBubbleAlignment alignment, RecyclerView.ViewHolder holder, List<BaseMessage> messageList, int position) { // Bind your custom view data here }});
What this does: Overrides the content view of the matched template by providing a MessagesViewHolderListener that inflates a custom layout in createView() and binds message data to it in bindView().
Apply the modified templates to the MessageList component:
Kotlin
Java
messageList.setTemplates(messageTemplates)
messageList.setTemplates(messageTemplates);
What this does: Passes the modified templates list to the MessageList component so it uses your customized templates when rendering message bubbles.
The MessageBubble structure is broken down into these views:
Leading view: Displays the sender’s avatar. It appears on the left of the MessageBubble for messages from others and on the right for messages from the current user.
Header view: Displays the sender’s name. This is useful in group chats where multiple users are sending messages.
Content view: The core of the MessageBubble where the message content (text, images, videos, etc.) is displayed.
Bottom view: Extends the MessageBubble with additional elements, such as link previews or a “load more” button for long messages. It is placed beneath the Content view.
Footer view: Displays the timestamp of the message and its delivery or read status. It is located at the bottom of the MessageBubble.
MessageTemplate provides methods that allow you to alter various properties of the MessageBubble, including the type and category of a message, and the appearance and behavior of the header, content, and footer sections.Type: Use setType() to set the type of CometChatMessage. This maps your MessageTemplate to the corresponding CometChatMessage.
What this does: Sets the message type on the template so the UI Kit knows which incoming messages this template applies to.
Category: Use setCategory() to set the category of a MessageTemplate. This creates a MessageTemplate with the specified category and links it with a CometChatMessage of the same category. Refer to the guide on Message Categories for a deeper understanding.
What this does: The createView() method inflates message_template_header_view.xml as the header view for every message. The bindView() method sets the sender’s name and a status emoji on the TextView, and is called every time a ViewHolder for that message type is bound.
Verify: Each text message bubble displays a custom header showing the sender’s name followed by ” • 🗓️ In meeting” in the primary color, replacing the default sender name header.
What this does: Defines a custom content layout with a CometChatImageBubble, a “Buy Now” label below it, and a hidden CometChatDeleteBubble that appears when the message is deleted.
Code:
Kotlin
Java
val templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.additionParameter) for (template in templates) { if (template.type == UIKitConstants.MessageType.IMAGE) { template.setContentView(object : MessagesViewHolderListener() { override fun createView( context: Context, cometChatMessageBubble: CometChatMessageBubble, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment ): View { return LayoutInflater.from(context).inflate(R.layout.image_bubble_content_view, null) } override fun bindView( context: Context, view: View, baseMessage: BaseMessage, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment, viewHolder: RecyclerView.ViewHolder, list: List<BaseMessage>, i: Int ) { if (view != null) { val deleteStyle: Int val bubbleStyle: Int if (messageBubbleAlignment == UIKitConstants.MessageBubbleAlignment.RIGHT) { deleteStyle = com.cometchat.chatuikit.R.style.CometChatIncomingMessageDeleteStyle bubbleStyle = com.cometchat.chatuikit.R.style.CometChatIncomingImageMessageBubbleStyle } else { deleteStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingDeleteBubbleStyle bubbleStyle = com.cometchat.chatuikit.R.style.CometChatOutgoingImageBubbleStyle } val linearLayout = view.findViewById<LinearLayout>(R.id.image_bubble_container) val cometchatImageBubble = view.findViewById<CometChatImageBubble>(R.id.imageBubble) val deletedBubble = view.findViewById<CometChatDeleteBubble>(com.cometchat.chatuikit.R.id.cometchat_delete_text_bubble) val mediaMessage = baseMessage as MediaMessage if (mediaMessage.deletedAt == 0L) { cometchatImageBubble.style = bubbleStyle deletedBubble.visibility = View.GONE cometchatImageBubble.visibility = View.VISIBLE val attachment = mediaMessage.attachment val file = Utils.getFileFromLocalPath(mediaMessage) cometchatImageBubble.setImageUrl( file, if (attachment != null) attachment.fileUrl else "", attachment?.fileExtension?.equals("gif", ignoreCase = true) ?: Utils.isGifFile(file) ) } else { linearLayout.visibility = View.GONE deletedBubble.visibility = View.VISIBLE deletedBubble.style = deleteStyle } } } }) break } }messageList.setTemplates(templates)
What this does: The createView() method inflates image_bubble_content_view.xml as the content view for every image message. The bindView() method handles displaying the image with CometChatImageBubble when the message is not deleted, and showing a CometChatDeleteBubble when the message has been deleted.
Verify: Image message bubbles display a CometChatImageBubble with a “Buy Now” label below it. If the message is deleted, the image is hidden and a delete bubble appears instead.
What you are changing: The status info area inside the message bubble, which displays delivery/read status indicators.
Where: MessagesViewHolderListener passed to template.setStatusInfoView() (and optionally template.setFooterView() for relocated status content)
Applies to: Any message type matched by the template (e.g., UIKitConstants.MessageType.TEXT)
Default behavior: Displays the message receipt and timestamp inside the bubble
Override: Pass a MessagesViewHolderListener to setStatusInfoView() that returns a minimal empty view, and move the status content to the footer view using setFooterView()
What this does: Defines a custom status info layout with a time TextView and a CometChatMessageReceipt view arranged horizontally, aligned to the end of the bubble.
Code:
Kotlin
Java
val templates = ChatConfigurator.getDataSource().getMessageTemplates(messageList.additionParameter) for (template in templates) { if (template.type == UIKitConstants.MessageType.TEXT) { template.setStatusInfoView(object : MessagesViewHolderListener() { override fun createView( context: Context, cometChatMessageBubble: CometChatMessageBubble, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment ): View { val view = View(context) val layoutParams = LinearLayout.LayoutParams( context.resources.getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_1dp), context.resources.getDimensionPixelSize(com.cometchat.chatuikit.R.dimen.cometchat_12dp) ) view.layoutParams = layoutParams return view } override fun bindView( context: Context, view: View, baseMessage: BaseMessage, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment, viewHolder: RecyclerView.ViewHolder, list: List<BaseMessage>, i: Int ) { } }) template.setFooterView(object : MessagesViewHolderListener() { override fun createView( context: Context, cometChatMessageBubble: CometChatMessageBubble, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment ): View { return LayoutInflater.from(context).inflate(R.layout.status_info_layout, null) } override fun bindView( context: Context, createdView: View, baseMessage: BaseMessage, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment, viewHolder: RecyclerView.ViewHolder, list: List<BaseMessage>, i: Int ) { val tvTime = createdView.findViewById<TextView>(R.id.time) val receipt = createdView.findViewById<CometChatMessageReceipt>(R.id.receipt) if (messageBubbleAlignment == UIKitConstants.MessageBubbleAlignment.RIGHT) { receipt.visibility = View.VISIBLE receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage)) } else { receipt.visibility = View.GONE } tvTime.text = SimpleDateFormat("hh:mm a").format(baseMessage.sentAt * 1000) } }) break } } messageList.setTemplates(templates)
What this does: The setStatusInfoView() replaces the default in-bubble status info with a minimal 1dp×12dp empty view. The setFooterView() inflates status_info_layout.xml as the footer, displaying the timestamp and message receipt outside the bubble. If the alignment is RIGHT (sent messages), the receipt icon is visible; if LEFT (received messages), the receipt icon is hidden.
Verify: Text message bubbles show the timestamp and delivery receipt below the bubble (in the footer area) instead of inside the bubble. Sent messages display both the time and receipt icon; received messages display only the time.
What this does: Defines a custom bottom view layout with an error icon and a red warning text, used to display a policy warning below the message content.
What this does: The createView() method inflates message_template_bottom_view.xml as the bottom view for every message. The bindView() method hides the bottom view by default and shows it only if the message has metadata and the message receipt equals Receipt.ERROR.
Verify: The bottom view is hidden by default. If a message has an error receipt (Receipt.ERROR) and non-null metadata, a red warning banner with an error icon and text appears below the message content.
What this does: The createView() method inflates a custom footer layout with a CometChatMessageReaction view. The bindView() method sets the background color based on alignment (primary color for sent messages, neutral color for received messages), applies the CometChatReactionStyle, and binds up to 4 reactions to the message.
Verify: Each message bubble displays a reactions bar in the footer area with a separator line above it. Sent message footers use the primary color background; received message footers use the neutral color background. Up to 4 reactions are displayed per message.
What you are changing: The entire message bubble, replacing the default combination of header, content, and footer views with a fully custom layout.
Where: MessagesViewHolderListener passed to template.setBubbleView()
Applies to: Any message type matched by the template (e.g., UIKitConstants.MessageType.TEXT)
Default behavior: The headerView, contentView, and footerView together form a message bubble
Override: Pass a MessagesViewHolderListener to setBubbleView() that inflates a completely custom bubble layout in createView() and binds data in bindView()
What this does: Defines a vector drawable for the right (outgoing) bubble background with a speech-bubble tail pointing right, using the primary color.
What this does: Defines the outgoing (sent) text bubble layout with a right-aligned bubble background, a text message TextView, a timestamp, and a CometChatMessageReceipt view.
What this does: Defines the incoming (received) text bubble layout with a left-aligned bubble background, a text message TextView, and a timestamp (no receipt icon for incoming messages).
Code:
Kotlin
Java
template.setBubbleView(object : MessagesViewHolderListener() { override fun createView( context: Context, messageBubble: CometChatMessageBubble, alignment: MessageBubbleAlignment ): View { return if (alignment == MessageBubbleAlignment.LEFT) LayoutInflater.from(context).inflate(R.layout.incoming_text_bubble_view, null) else LayoutInflater.from(context).inflate(R.layout.outgoing_text_bubble_view, null) } override fun bindView( context: Context, createdView: View, message: BaseMessage, alignment: MessageBubbleAlignment, holder: RecyclerView.ViewHolder, messageList: List<BaseMessage>, position: Int ) { val textView = createdView.findViewById<TextView>(R.id.text_message) val tvTime = createdView.findViewById<TextView>(R.id.time) if (alignment == MessageBubbleAlignment.RIGHT) { val receipt = createdView.findViewById<CometChatMessageReceipt>(R.id.receipt) receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(message)) } val textMessage = message as TextMessage tvTime.text = SimpleDateFormat("hh:mm a").format(textMessage.sentAt * 1000) textView.text = textMessage.text } })
What this does: The createView() method inflates incoming_text_bubble_view.xml if the alignment is LEFT (received messages) or outgoing_text_bubble_view.xml if the alignment is RIGHT (sent messages). The bindView() method sets the message text, timestamp, and receipt icon (for sent messages only), completely replacing the default bubble structure.
Verify: Text messages display with custom speech-bubble-shaped backgrounds — outgoing messages use the primary color with a right-pointing tail, incoming messages use the neutral color with a left-pointing tail. Each bubble shows the message text, timestamp, and (for sent messages) a delivery receipt icon.
What this does: Creates a custom “Refresh” option using CometChatMessageOption with an ID of "REFRESH", a label, an icon, and a click handler that shows a toast. This option is prepended to the default options list retrieved from CometChatUIKit.getDataSource().getMessageOptions(), so the “Refresh” option appears first in the long-press action sheet for all message types.
Verify: Long-pressing any message displays an action sheet with “Refresh” as the first option, followed by the default options (Reply, Forward, Edit, Delete, etc.). Tapping “Refresh” shows a toast message “Refresh clicked”.
What this does: Creates a CustomMessage with type "card" containing contact data (contact_name, contact_avatar, contact_number) as a JSONObject, and sends it using CometChatUIKit.sendCustomMessage().
What this does: Defines a contact card layout using MaterialCardView with a CometChatAvatar, contact name, timestamp, receipt icon, a separator, and two action buttons (“Add Contact” and “Message”).
Creating and registering the new template:
Kotlin
Java
val contactTemplate = CometChatMessageTemplate() contactTemplate.setType("card") contactTemplate.setCategory(UIKitConstants.MessageCategory.CUSTOM) contactTemplate.setBubbleView(object : MessagesViewHolderListener() { override fun createView( context: Context, cometChatMessageBubble: CometChatMessageBubble, messageBubbleAlignment: UIKitConstants.MessageBubbleAlignment ): View { return LayoutInflater.from(context).inflate(R.layout.contact_card, null) } override fun bindView( context: Context, view: View, baseMessage: BaseMessage, alignment: UIKitConstants.MessageBubbleAlignment, viewHolder: RecyclerView.ViewHolder, list: List<BaseMessage>, i: Int ) { val layoutParams = LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT ) view.layoutParams = layoutParams val avatar = view.findViewById<CometChatAvatar>(R.id.avatar) val name = view.findViewById<TextView>(R.id.contactName) val time = view.findViewById<TextView>(R.id.time) val receipt = view.findViewById<CometChatMessageReceipt>(R.id.receipt) val customMessage = baseMessage as CustomMessage val jsonObject = customMessage.customData try { name.text = jsonObject.getString("contact_name") avatar.avatar = jsonObject.getString("contact_avatar") } catch (e: Exception) { e.printStackTrace() } if (alignment == UIKitConstants.MessageBubbleAlignment.RIGHT) { receipt.visibility = View.VISIBLE receipt.setMessageReceipt(MessageReceiptUtils.MessageReceipt(baseMessage)) } else { receipt.visibility = View.GONE } time.text = SimpleDateFormat("hh:mm a").format(baseMessage.getSentAt() * 1000) } }) messageTemplates.add(contactTemplate) messageList.setTemplates(messageTemplates)
What this does: Creates a new CometChatMessageTemplate with type "card" and category UIKitConstants.MessageCategory.CUSTOM. The setBubbleView() inflates contact_card.xml and binds the contact name, avatar, timestamp, and receipt from the CustomMessage’s customData JSON. The new template is added to the existing templates list and applied to the MessageList via setTemplates(). This renders the custom “card” message as a contact card in the chat.
Verify: Custom messages with type "card" appear in the MessageList as a purple contact card showing the contact’s avatar, name, timestamp, delivery receipt (for sent messages), and two action buttons (“Add Contact” and “Message”).