Message List View

Last Edit: Nov 27 2020

The message list renders a list of messages. It implements all the features you expect from a chat/message list view:

  • Reactions

  • Editing

  • Typing indicators

  • Read state

  • Rich URL previews

  • Threads

The example below shows how to use the MessageListView in your layout:

    android:layout_height="match_parent" />

To render the list of messages you need to connect the view to the MessageListViewModel using MessageListViewModelBinding:

// Get a ViewModel instance
val messageListViewModel: MessageListViewModel by viewModels { ChannelViewModelFactory(channel.cid) }

// Bind ViewModel and View together
messagesViewModel.bindView(messageListView, lifecycleOwner)

// Get a ViewModel instance
ChannelViewModelFactory factory = new ChannelViewModelFactory(channel.getCid());
MessageListViewModel viewModel = new ViewModelProvider(this, factory)

// Bind ViewModel and View together
MessageListViewModelBinding.bind(viewModel, messageListView, lifecycle);

The view model provides the view with:

  • The list of messages

  • The ability to mark messages as read

  • Pagination/ loading more content

  • Keeping track if there are new messages (that are not shown since you're scrolled up)

  • The current channel

  • Edit message state

  • Start thread state

  • Button to scroll to the bottom.

  • Count of new messages.


The following listeners can be set:

  • setMessageClickListener

  • setMessageLongClickListener

  • setMessageRetryListener

  • setAttachmentClickListener

  • setReactionViewClickListener

  • setUserClickListener

  • setReadStateClickListener

  • setOnStartThreadListener


The following handlers can be set:

  • setEndRegionReachedHandler

  • setLastMessageReadHandler

  • setOnMessageEditHandler

  • setOnMessageDeleteHandler

  • setOnStartThreadHandler

  • setOnMessageFlagHandler

  • setOnSendGiphyHandler

  • setOnMessageRetryHandler


The message list view exposes multiple methods which might be helpful if you decide not to use default view model but create your own controller instead:

  • init()

  • setScrollButtonBehaviour()

  • setNewMessagesBehaviour()

  • setScrollButtonBackgroundResource()

  • setScrollButtonBackground()

  • setScrollButtonIconResource()

  • setScrollButtonIcon()

  • setAttachmentViewHolderFactory()

  • setMessageViewHolderFactory()

  • setBubbleHelper()

  • displayNewMessage()

  • scrollToBottom()

  • setLoadingView()

  • setEmptyStateView()

Customizing the message list using attributes

You can use the following properties in your XML to change your MessageListView:


Name Type Description Default Optional
app:streamNewMessagesBehaviour enum. Options: 1- scroll_to_bottom, 2 - count_new_messages Behaviour for new messages when user is scrolling in the chat. count_new_messages

Scroll to bottom button

Name Type Description Default Optional
app:streamNewMessagesTextSingle string Text for one new message. Example: "1 New message" -
app:streamNewMessagesTextPlural string Text for many new messages. Example: "5 New messages" -
app:streamScrollButtonBackground reference Background of the scroll to bottom button - This can be useful to change the color and shape of the button. round shape with accent color
app:streamButtonIcon reference Icon in the button Bottom arrow
app:streamDefaultScrollButtonEnabled boolean Enable or disable the Scroll Button True


Name Type Description Default Optional
app:streamAvatarWidth dimension 32dp
app:streamAvatarHeight dimension 32dp
app:streamAvatarBorderWidth dimension 3dp
app:streamAvatarBorderColor color WHITE
app:streamAvatarBackGroundColor color stream_gray_dark
app:streamAvatarTextSize dimension 14sp
app:streamAvatarTextColor color WHITE
app:streamAvatarTextStyle normal, bold, italic bold
app:streamAvatarTextFont reference -
app:streamAvatarTextFontAssets string -

Read State

Name Type Description Default Optional
app:streamShowReadState boolean true
app:streamReadStateAvatarWidth dimension 14dp
app:streamReadStateAvatarHeight dimension 14dp
app:streamReadStateTextSize dimension 8sp
app:streamReadStateTextColor color BLACK
app:streamReadStateTextStyle normal, bold, italic bold
app:streamReadStateTextFont reference -
app:streamReadStateTextFontAssets string -
app:streamShowDeliveredState boolean true
app:streamShowReadState boolean true


Name Type Description Default Optional
app:streamReactionEnabled boolean true
app:streamrReactionViewBgDrawable reference -
app:streamReactionViewBgColor color #292929
app:streamReactionViewEmojiSize dimension 12sp
app:streamReactionViewEmojiMargin dimension 1dp
app:streamReactionInputbgColor color #292929
app:streamReactionInputEmojiSize dimension 27sp
app:streamReactionInputEmojiMargin dimension 5dp


Name Type Description Default Optional
app:streamMessageTextSizeMine dimension 15sp
app:streamMessageTextSizeTheirs dimension 15sp
app:streamMessageTextColorMine color BLACK
app:streamMessageTextColorTheirs color BLACK
app:streamMessageTextStyleMine normal, bold, italic normal
app:streamMessageTextStyleTheirs normal, bold, italic normal
app:streamMessageTextFontMine reference -
app:streamMessageTextFontTheirs reference -
app:streamMessageTextFontMineAssets string -
app:streamMessageTextFontTheirsAssets string -
app:streamMessageBubbleDrawableMine reference -
app:streamMessageBubbleDrawableTheirs reference -
app:streamMessageTopLeftCornerRadiusMine dimension 16dp
app:streamMessageTopRightCornerRadiusMine dimension 16dp
app:streamMessageBottomRightCornerRadiusMine dimension 2dp
app:streamMessageBottomLeftCornerRadiusMine dimension 16dp
app:streamMessageTopLeftCornerRadiusTheirs dimension 16dp
app:streamMessageTopRightCornerRadiusTheirs dimension 16dp
app:streamMessageBottomRightCornerRadiusTheirs dimension 16dp
app:streamMessageBottomLeftCornerRadiusTheirs dimension 2dp
app:streamMessageBackgroundColorMine color #0D000000
app:streamMessageBackgroundColorTheirs color WHITE
app:streamMessageBorderColorMine color #14000000
app:streamMessageBorderColorTheirs color #14000000
app:streamMessageBorderWidthMine dimension 1dp
app:streamMessageBorderWidthTheirs dimension 1dp
app:streamMessageLinkTextColorMine color -
app:streamMessageLinkTextColorTheirs color -


Name Type Description Default Optional
app:streamAttachmentBackgroundColorMine color streamMessageBackgroundColorMine
app:streamAttachmentBackgroundColorTheirs color streamMessageBackgroundColorTheirs
app:streamAttachmentBorderColorMine color streamMessageBorderColorMine
app:streamAttachmentBorderColorTheirs color streamMessageBorderColorTheirs
app:streamAttachmentTitleTextSizeMine dimension 13sp
app:streamAttachmentTitleTextSizeTheirs dimension 13sp
app:streamAttachmentTitleTextColorMine color #026DFE
app:streamAttachmentTitleTextColorTheirs color #026DFE
app:streamAttachmentTitleTextStyleMine normal, bold, italic bold
app:streamAttachmentTitleTextStyleTheirs normal, bold, italic bold
app:streamAttachmentTitleTextFontMine reference -
app:streamAttachmentTitleTextFontTheirs reference -
app:streamAttachmentTitleTextFontAssetsMine string -
app:streamAttachmentTitleTextFontAssetsTheirs string -
app:streamAttachmentDescriptionTextSizeMine dimension 11sp
app:streamAttachmentDescriptionTextSizeTheirs dimension 11sp
app:streamAttachmentDescriptionTextColorMine color stream_gray_dark
app:streamAttachmentDescriptionTextColorTheirs color stream_gray_dark
app:streamAttachmentDescriptionTextStyleMine normal, bold, italic normal
app:streamAttachmentDescriptionTextStyleTheirs normal, bold, italic normal
app:streamAttachmentDescriptionTextFontMine reference -
app:streamAttachmentDescriptionTextFontTheirs reference -
app:streamAttachmentDescriptionTextFontAssetsMine string -
app:streamAttachmentDescriptionTextFontAssetsTheirs string -
app:streamAttachmentFileSizeTextSizeMine dimension 12sp
app:streamAttachmentFileSizeTextSizeTheirs dimension 12sp
app:streamAttachmentFileSizeTextColorMine color stream_gray_dark
app:streamAttachmentFileSizeTextColorTheirs color stream_gray_dark
app:streamAttachmentFileSizeTextStyleMine normal, bold, italic bold
app:streamAttachmentFileSizeTextStyleTheirs normal, bold, italic bold
app:streamAttachmentFileSizeTextFontMine reference -
app:streamAttachmentFileSizeTextFontTheirs reference -
app:streamAttachmentFileSizeTextFontAssetsMine string -
app:streamAttachmentFileSizeTextFontAssetsTheirs string -

Date Separator

Name Type Description Default Optional
app:streamDateSeparatorDateTextSize dimension 12sp
app:streamDateSeparatorDateTextColor color stream_gray_dark
app:streamDateSeparatorDateTextStyle normal, bold, italic bold
app:streamDateSeparatorDateTextFont reference -
app:streamDateSeparatorDateTextFontAssets string -
app:streamDateSeparatorLineWidth dimension 1dp
app:streamDateSeparatorLineColor color stream_gray_dark
app:streamDateSeparatorLineDrawable reference -

Message details

Name Type Description Default Optional
app:streamMessageUserNameTextSize dimension 11sp
app:streamMessageUserNameTextColor color stream_gray_dark
app:streamMessageUserNameTextStyle normal, bold, italic normal
app:streamMessageUserNameTextFont reference -
app:streamMessageUserNameTextFontAssets string -
app:streamMessageDateTextSizeMine dimension 11sp
app:streamMessageDateTextSizeTheirs dimension 11sp
app:streamMessageDateTextColorMine color stream_gray_dark
app:streamMessageDateTextColorTheirs color stream_gray_dark
app:streamMessageDateTextStyleMine normal, bold, italic normal
app:streamMessageDateTextStyleTheirs normal, bold, italic normal
app:streamMessageDateTextFontMine reference -
app:streamMessageDateTextFontAssetsMine string -
app:streamUserNameShow boolean true
app:streamMessageDateShow boolean true

Customizing the message list - BubbleHelper

Message Bubbles can be quite complex in messaging apps. Many messaging apps will change the bubble layout based on:

  • The message position in a group of messages (top, middle, bottom)

  • The overall position of the message on the screen

  • If the message is yours or written by someone else

  • If the message has attachments

To allow you to customize the message bubble rendering we allow you to set your own message Bubble Helper. Here's an example of how to set a custom bubble helper.

MessageListView messageList = findViewById(;
messageList.setBubbleHelper(new MessageListView.BubbleHelper() {
    public Drawable getDrawableForMessage(Message message, Boolean mine, List<MessageListItem.Position> positions) {
        return null;

    public Drawable getDrawableForAttachment(Message message, Boolean mine, List<MessageListItem.Position> positions, Attachment attachment) {
        return null;

    public Drawable getDrawableForAttachmentDescription(Message message, Boolean mine, List<MessageListItem.Position> positions) {
        return null;

val messageList = findViewById(
messageList.setBubbleHelper(object: MessageListView.BubbleHelper {
    override fun getDrawableForAttachment(
        message: Message,
        mine: Boolean,
        positions: List<MessageListItem.Position>,
        attachment: Attachment
    ): Drawable {
        TODO("not implemented")

    override fun getDrawableForAttachmentDescription(
        message: Message,
        mine: Boolean,
        positions: List<MessageListItem.Position>
    ): Drawable {
        TODO("not implemented")

    override fun getDrawableForMessage(
        message: Message,
        mine: Boolean,
        positions: List<MessageListItem.Position>
    ): Drawable {
        TODO("not implemented")

For some messaging use cases, you'll run into the issue that you need to create many different drawables. One library that can help with that is DrawableToolbox which simplifies the programmatic creation of drawables.

Custom Attachment Type

You can customize the layout for a specific type of message or attachment. Example use cases include adding a form, a live location, a checkout flow, etc.

These are the steps for creating your own attachment type:

  1. Implement an Attachment ViewHolder, with your custom layout

  2. Create an AttachmentViewHolderFactory that creates instances of your ViewHolder

  3. Tell the MessageListView to use your custom AttachmentViewHolderFactory

The Kotlin Chat Tutorial explains this in more detail.

Creating custom scroll-to-bottom button

Although it is possible to customize the default button, sometimes a user may want a completely different view.

As MessageListView extends from ConstraintLayout, any view can be inserted inside of it and used as the button to scroll to button and show the count of new messages.


            android:text="Scroll - 1 New message"

Then the behaviour of the button can be set with the method setScrollButtonBehaviour implementing the interface MessageListView.ScrollButtonBehaviour, as an example:

messageListView.setScrollButtonBehaviour(new MessageListView.ScrollButtonBehaviour() {
    public void userScrolledUp() {
    public void userScrolledToTheBottom() {
    public void onUnreadMessageCountChanged(int count) {
        if (count == 0) {
        } else if (count == 1) {
            scrollBtn.setText("Scroll - 1 New Message");
        } else {
            scrollBtn.setText("Scroll - " + count + " New Messages");

messageListView.setScrollButtonBehaviour(object : MessageListView.ScrollButtonBehaviour {
    override fun userScrolledUp() {
        scrollBtn.visibility = View.VISIBLE

    override fun userScrolledToTheBottom() {
        scrollBtn.visibility = View.GONE

    override fun onUnreadMessageCountChanged(count: Int) {
        when (count) {
            0 -> scrollBtn.text = "Scroll"
            1 -> scrollBtn.text = "Scroll - 1 New Message"
            else -> scrollBtn.text = "Scroll - $count New Messages"