Skip to main content
View Slots let you swap out specific parts of a component’s list item — the avatar area, title, subtitle, trailing section, or the entire row — while keeping the rest of the component’s behavior intact.

The ViewHolderListener Pattern

Every list-based component defines a ViewHolderListener abstract class (e.g., ConversationsViewHolderListener) with two callbacks:
CallbackPurpose
createView(Context context, CometchatConversationsListItemsBinding listItem)Return a View that will be placed in the slot. Called once when the ViewHolder is created.
bindView(Context context, View createdView, Conversation conversation, RecyclerView.ViewHolder holder, List<Conversation> conversationList, int position)Bind data to your custom view. Called every time the item is bound (scroll, update). createdView is the view returned by createView, and the full conversation list and holder are provided for context.

Available View Slots

SetterRegionDescription
setLeadingViewLeft sectionReplaces the avatar / leading area of each list item.
setTitleViewTitle textReplaces the name / title text area.
setSubtitleViewSubtitle textReplaces the last message preview area.
setTrailingViewRight sectionReplaces the timestamp / badge / trailing area.
setItemViewEntire rowReplaces the entire list item layout.

Slot-Level vs Full Item Replacement

Use slot-level setters (setLeadingView, setTitleView, setSubtitleView, setTrailingView) when you want to customize one region while keeping the default layout for everything else. Use setItemView when you need complete control over the entire row layout.
When you use setItemView, all other slot setters are ignored since the entire row is replaced.

Example: Custom Leading View

Replace the default avatar with a custom view that shows the first letter of the conversation name in a colored circle:
conversations.setLeadingView(object : ConversationsViewHolderListener() {
    override fun createView(
        context: Context,
        listItem: CometchatConversationsListItemsBinding
    ): View {
        val textView = TextView(context).apply {
            layoutParams = ViewGroup.LayoutParams(48.dp, 48.dp)
            gravity = Gravity.CENTER
            textSize = 18f
            setTextColor(Color.WHITE)
        }
        return textView
    }

    override fun bindView(
        context: Context,
        createdView: View,
        conversation: Conversation,
        holder: RecyclerView.ViewHolder,
        conversationList: List<Conversation>,
        position: Int
    ) {
        val textView = createdView as TextView
        val name = conversation.conversationWith?.name ?: ""
        textView.text = name.firstOrNull()?.uppercase() ?: "?"
        textView.background = GradientDrawable().apply {
            shape = GradientDrawable.OVAL
            setColor(Color.parseColor("#6851D6"))
        }
    }
})

Example: Custom Subtitle View

Show a “typing…” indicator or a custom last message format in the subtitle area:
conversations.setSubtitleView(object : ConversationsViewHolderListener() {
    override fun createView(
        context: Context,
        listItem: CometchatConversationsListItemsBinding
    ): View {
        return TextView(context).apply {
            maxLines = 1
            ellipsize = TextUtils.TruncateAt.END
        }
    }

    override fun bindView(
        context: Context,
        createdView: View,
        conversation: Conversation,
        holder: RecyclerView.ViewHolder,
        conversationList: List<Conversation>,
        position: Int
    ) {
        val textView = createdView as TextView
        val lastMessage = conversation.lastMessage
        textView.text = when (lastMessage) {
            is TextMessage -> lastMessage.text
            is MediaMessage -> "📎 ${lastMessage.attachment?.fileExtension ?: "Media"}"
            else -> "New conversation"
        }
    }
})

Toolbar Overflow Menu

Use setOverflowMenu(View) to inject a custom view into the component’s toolbar area. This is separate from the list item view slots — it customizes the toolbar, not individual rows.
val menuButton = ImageButton(context).apply {
    setImageResource(R.drawable.ic_filter)
    setOnClickListener { /* show filter dialog */ }
}
conversations.setOverflowMenu(menuButton)