Press enter to see results or esc to cancel.

Android-chat-tutorial

Android Chat Tutorial: Building a Messaging UI

Despite their growing prevalence, chat and messaging apps continue to be tedious to implement. Official documentation is nonexistent, while unofficial tutorials are scarce and largely outdated.

Google Allo's Android chat UI

Colorful chat bubbles filled with text, as well as images and even playable media–how do they do it? The answer is surprisingly simple: RecyclerViews, coupled with the ViewHolder pattern. In this tutorial, we will traverse through the steps in building a quality messaging UI.

 

Setting up the Activity

In this tutorial, we will create a dedicated activity, called MessageListActivity, to host our messages. The primary component in this activity will be a RecyclerView that fills most of the screen. To keep ahead of the curve, a ConstraintLayout will be used as the root ViewGroup.

In addition to displaying message history, a chat UI typically needs to allow the user to send messages via a chatbox. Using constraints, we can position this chatbox at the bottom of the screen. This will have the effect of anchoring it to the soft input keyboard that pops up when the user types something.

 

/layout/activity_message_list.xml

The end result is a flexible chatbox that expands according to the length of the message being typed, and a RecyclerView that fills the remaining space with past messages.

layout 1

 

Creating a list item for each message

As typical in ListViews and RecyclerViews, a separate XML file will be used to define the layout of each item (in this case, a message). A prevalent UI pattern is for each message to additionally contain the sender’s name, profile image, and the date or time that the message was sent.

Screen Shot 2017-04-04 at 5.09.24 PM

However, it may be redundant to repeatedly display the sender’s own profile image and name, especially when a right-aligned chat bubble already signifies a message sent by oneself. Consequently, most chat clients choose to discard these components altogether. We will also follow this pattern and create two different ViewHolder‘s: SentMessageHolder, for messages that “I” have sent, and ReceivedMessageHolder, for messages sent by others.

To translate the above image into an XML file, we must first implement a chat bubble. Once again, this is surprisingly simple: set a rounded rectangle as the background for a TextView. Adjust the paddings, align the text, and voila! We now have a chat bubble that houses a message.

 

/drawable/rounded_rectangle_orange.xml

This produces the friendly chat bubble below.

Screen Shot 2017-04-04 at 5.19.36 PM

With constraints, you can position the other TextViews appropriately. One thing to note is that your root layout’s height should be set to wrap_content–that way, it can accommodate longer messages as well as one liners. Another important note is that the message body’s max_width should be set to a certain threshold. If not, the chat bubble will stretch in width until it fills the screen, which is quite unaesthetic.

 

/layout/item_message_received.xml

Screen Shot 2017-04-04 at 5.25.31 PM

 

For sent messages, simply align the chat bubble to the right, and remove the name and profile image.

 

/layout/item_message_sent.xml

 

Creating an Adapter for the RecyclerView

In order to populate our RecyclerView with the XML items that we have created, we must now create an adapter that extends RecylerView.Adapter. This adapter will store a list of messages, determine whether it is a sent message or a received message, and finally inflate the appropriate layout within a RecyclerView.

But before venturing any further, we need a list of messages! However, engineering a backend for real-time messaging is quite beyond the scope of this tutorial, and therefore we will proceed with the models in SendBird’s chat SDK, which roughly takes on the following structure:

 

Generic Message and User models

The vast majority of messaging implementations are designed this way, so hopefully you will be able to follow this guide with minimal changes to your own code.

Now, let us return to our adapter, which unfortunately does not exist yet. No worries–we will create one now, and name it MessageListAdapter. Its function is to hold a List of Messages that will be displayed within a RecyclerView.

 

MessageListAdapter.java

By default, an adapter requires at least one RecyclerView.ViewHolder, which is basically a layout that can be inflated and bound to the objects that it holds. In our case, two ViewHolders are needed: a SentMessageHolder to hold “my” messages, and a ReceivedMessageHolder to hold messages that “I” have received from others. These will be created as private inner classes of MessageListAdapter.

Each ViewHolder holds member views which can be bound to some information contained in a message. For example, TextView messageText binds to a message’s content, while nameText binds to the name of the message’s sender.

One convenient pattern suggested by Antonio Leiva is implementing a bind(object) method within the ViewHolder class. In effect, view binding is delegated to within the ViewHolder class as opposed to onBindViewHolder. This produces cleaner code amidst multiple ViewHolders and ViewTypes, and additionally allows OnClickListeners to be easily added if necessary.

 

ReceivedMessageHolder.java

SentMessageHolder would be identical except that it does not have a nameText and profileImage.

Once the ViewHolder is completed, we now turn back to our adapter and override the necessary methods to (1) obtain a message from mMessageList, (2) determine whether it is a sent message or a received message, (3) inflate the appropriate layout for the ViewHolder, and (4) pass the message to the ViewHolder for binding. Implementation of this process is standard boilerplate for most types of adapters, and also pretty self-explanatory; therefore, the code for the full adapter will be shown without further explanation.

 

MessageListAdapter.java

Just like that, our adapter is completed. We can now display a list of messages, both sent and received, in the chat bubbles that we have defined earlier.

 

Putting it all together

All the components have been created, and now the only thing left to do is to initialize them inside our Activity. Instantiate a RecyclerView and a MessageListAdapter with a list of messages, and voila! You have replicated a quality messaging UI.

 

MessageListActivity.java

For examples on building advanced chat user interfaces, such as image previews, animated GIFs within chat bubbles, et cetera, make a visit to SendBird’s open source sample UI app! It expands upon the use of RecyclerViews and adapters as covered in this tutorial to create a production-level chat app with diverse features.

Comments

Leave a Comment