Click here to Skip to main content
15,881,802 members
Articles / Mobile Apps / Android
Tip/Trick

Designing Android Chat Bubble (Chat UI)

Rate me:
Please Sign up or sign in to vote.
4.68/5 (17 votes)
17 Apr 2015CPOL2 min read 218.5K   20   30
Creating Simple Android Chat Bubble or Chat UI Layout

Introduction

In this tip, we can see how a Chat Bubble (simply a Chat UI) is designed.

Background

It's common nowadays to have a Chat feature in many of the Mobile Applications. So here, we discuss quickly about how to design one for us. We will try to keep it short and crisp as much as possible to maintain the simplicity.

Screenshot

Image 1

Using the Code

We will need to use a ListView to display the Chat list, listItem for displaying the individual Chat messages , Adapter to fill the ListView, Model Class which represents the Chat Messages and most important thing - 9 patch Images. The simplest explanation for 9 patch image will be an image which is set as background (Bubbles) and stretches accordingly with the text size. And its created just by saving any png image with an extension format. 9.png.

First, we start with creating an Activity and its Layout file which represents our Chat UI.

activity_chat.xml

XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp">

        <EditText
            android:id="@+id/messageEdit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_toLeftOf="@+id/chatSendButton"
            android:autoText="true"
            android:hint="type message" />

        <Button
            android:id="@+id/chatSendButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:background="@color/background_floating_material_dark"
            android:text="Send MSG"
            android:textColor="@color/background_material_light"/>

        <ListView
            android:id="@+id/messagesContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="false"
            android:layout_alignParentTop="false"
            android:layout_marginBottom="20dp"
            android:layout_above="@+id/messageEdit"
            android:layout_below="@+id/meLbl"
            android:layout_marginTop="10dp"
            android:listSelector="@android:color/transparent"
            android:transcriptMode="alwaysScroll"
            android:divider="@null" />

        <TextView
            android:id="@+id/meLbl"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left|center_vertical"
            android:text="MySelf"
            android:singleLine="false"
            android:textSize="20dp" />

        <TextView
            android:id="@+id/friendLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="Friend"
            android:textSize="20dp" />

    </RelativeLayout>
</LinearLayout>

ChatActivity.java

Java
public class ChatActivity extends ActionBarActivity {

    private EditText messageET;
    private ListView messagesContainer;
    private Button sendBtn;
    private ChatAdapter adapter;
    private ArrayList<ChatMessage> chatHistory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        initControls();
    }
   
    private void initControls() {
        messagesContainer = (ListView) findViewById(R.id.messagesContainer);
        messageET = (EditText) findViewById(R.id.messageEdit);
        sendBtn = (Button) findViewById(R.id.chatSendButton);

        TextView meLabel = (TextView) findViewById(R.id.meLbl);
        TextView companionLabel = (TextView) findViewById(R.id.friendLabel);
        RelativeLayout container = (RelativeLayout) findViewById(R.id.container);
        companionLabel.setText("My Buddy");// Hard Coded
        loadDummyHistory();

        sendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String messageText = messageET.getText().toString();
                if (TextUtils.isEmpty(messageText)) {
                    return;
                }

                ChatMessage chatMessage = new ChatMessage();
                chatMessage.setId(122);//dummy
                chatMessage.setMessage(messageText);
                chatMessage.setDate(DateFormat.getDateTimeInstance().format(new Date()));
                chatMessage.setMe(true);

                messageET.setText("");

                displayMessage(chatMessage);
            }
        });
    }

    public void displayMessage(ChatMessage message) {
        adapter.add(message);
        adapter.notifyDataSetChanged();
        scroll();
    }

    private void scroll() {
        messagesContainer.setSelection(messagesContainer.getCount() - 1);
    }

    private void loadDummyHistory(){

        chatHistory = new ArrayList<ChatMessage>();

        ChatMessage msg = new ChatMessage();
        msg.setId(1);
        msg.setMe(false);
        msg.setMessage("Hi");
        msg.setDate(DateFormat.getDateTimeInstance().format(new Date()));
        chatHistory.add(msg);
        ChatMessage msg1 = new ChatMessage();
        msg1.setId(2);
        msg1.setMe(false);
        msg1.setMessage("How r u doing???");
        msg1.setDate(DateFormat.getDateTimeInstance().format(new Date()));
        chatHistory.add(msg1);

        adapter = new ChatAdapter(ChatActivity.this, new ArrayList<ChatMessage>());
        messagesContainer.setAdapter(adapter);

                for(int i=0; i<chatHistory.size(); i++) {
                    ChatMessage message = chatHistory.get(i);
                    displayMessage(message);
                }
    }
}

List Item which shows the individual chat messages and the Background of this text will be set as Chat Bubble (our 9 patch image).

XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <LinearLayout
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:orientation="vertical">

        <TextView
            android:id="@+id/txtInfo"
            android:layout_width="wrap_content"
            android:layout_height="30sp"
            android:layout_gravity="right"
            android:textSize="12sp"
            android:textColor="@android:color/darker_gray" />

        <LinearLayout
            android:id="@+id/contentWithBackground"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:background="@drawable/in_message_bg"
            android:paddingLeft="10dp"
            android:paddingBottom="10dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txtMessage"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@android:color/black"
                android:maxWidth="240dp" />

        </LinearLayout>

    </LinearLayout>
</RelativeLayout>

Now we require a Model Class for representing the Chat Message and an Adapter to fill it for the ListView.

ChatMessage.java

Java
public class ChatMessage {
    private long id;
    private boolean isMe;
    private String message;
    private Long userId;
    private String dateTime;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public boolean getIsme() {
        return isMe;
    }
    public void setMe(boolean isMe) {
        this.isMe = isMe;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public long getUserId() {
        return userId;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }

    public String getDate() {
        return dateTime;
    }

    public void setDate(String dateTime) {
        this.dateTime = dateTime;
    }
}

ChatAdapter.java

As usual, we use ViewHolder pattern for efficiency when recreating each items in the Listview. LayoutParams are for designing the Layout left or right aligned according to the Chat Message Send or Received. A dummy boolean value is used as the property to check whether its Send or Received for simplicity .

Java
public class ChatAdapter extends BaseAdapter {

    private final List<ChatMessage> chatMessages;
    private Activity context;

    public ChatAdapter(Activity context, List<ChatMessage> chatMessages) {
        this.context = context;
        this.chatMessages = chatMessages;
    }

    @Override
    public int getCount() {
        if (chatMessages != null) {
            return chatMessages.size();
        } else {
            return 0;
        }
    }

    @Override
    public ChatMessage getItem(int position) {
        if (chatMessages != null) {
            return chatMessages.get(position);
        } else {
            return null;
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        ChatMessage chatMessage = getItem(position);
        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) {
            convertView = vi.inflate(R.layout.list_item_chat_message, null);
            holder = createViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        boolean myMsg = chatMessage.getIsme() ;//Just a dummy check 
        		//to simulate whether it me or other sender
        setAlignment(holder, myMsg);
        holder.txtMessage.setText(chatMessage.getMessage());
        holder.txtInfo.setText(chatMessage.getDate());

        return convertView;
    }

    public void add(ChatMessage message) {
        chatMessages.add(message);
    }

    public void add(List<ChatMessage> messages) {
        chatMessages.addAll(messages);
    }

    private void setAlignment(ViewHolder holder, boolean isMe) {
        if (!isMe) {
            holder.contentWithBG.setBackgroundResource(R.drawable.in_message_bg);

            LinearLayout.LayoutParams layoutParams = 
            	(LinearLayout.LayoutParams) holder.contentWithBG.getLayoutParams();
            layoutParams.gravity = Gravity.RIGHT;
            holder.contentWithBG.setLayoutParams(layoutParams);

            RelativeLayout.LayoutParams lp = 
            	(RelativeLayout.LayoutParams) holder.content.getLayoutParams();
            lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
            lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            holder.content.setLayoutParams(lp);
            layoutParams = (LinearLayout.LayoutParams) holder.txtMessage.getLayoutParams();
            layoutParams.gravity = Gravity.RIGHT;
            holder.txtMessage.setLayoutParams(layoutParams);

            layoutParams = (LinearLayout.LayoutParams) holder.txtInfo.getLayoutParams();
            layoutParams.gravity = Gravity.RIGHT;
            holder.txtInfo.setLayoutParams(layoutParams);
        } else {
            holder.contentWithBG.setBackgroundResource(R.drawable.out_message_bg);

            LinearLayout.LayoutParams layoutParams = 
            	(LinearLayout.LayoutParams) holder.contentWithBG.getLayoutParams();
            layoutParams.gravity = Gravity.LEFT;
            holder.contentWithBG.setLayoutParams(layoutParams);

            RelativeLayout.LayoutParams lp = 
            	(RelativeLayout.LayoutParams) holder.content.getLayoutParams();
            lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
            lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            holder.content.setLayoutParams(lp);
            layoutParams = (LinearLayout.LayoutParams) holder.txtMessage.getLayoutParams();
            layoutParams.gravity = Gravity.LEFT;
            holder.txtMessage.setLayoutParams(layoutParams);

            layoutParams = (LinearLayout.LayoutParams) holder.txtInfo.getLayoutParams();
            layoutParams.gravity = Gravity.LEFT;
            holder.txtInfo.setLayoutParams(layoutParams);
        }
    }

    private ViewHolder createViewHolder(View v) {
        ViewHolder holder = new ViewHolder();
        holder.txtMessage = (TextView) v.findViewById(R.id.txtMessage);
        holder.content = (LinearLayout) v.findViewById(R.id.content);
        holder.contentWithBG = (LinearLayout) v.findViewById(R.id.contentWithBackground);
        holder.txtInfo = (TextView) v.findViewById(R.id.txtInfo);
        return holder;
    }

    private static class ViewHolder {
        public TextView txtMessage;
        public TextView txtInfo;
        public LinearLayout content;
        public LinearLayout contentWithBG;
    }
}

Now, that's all we need to accomplish our task of designing a Chat Bubble. This sample was created using Android Studio IDE. I have posted the complete code which can be downloaded.

Points of Interest

The sample is designed for making it easy to try it yourself. Happy coding. :) Please do contact me in case of any doubts or queries.

History

  • 17th April, 2015: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Technovibe Solutions
India India
A web developer by profession in Microsoft technology stack and later into Mobile App Development. Indulges in a variety of hobbies such as travelling, photography, driving , biking etc.

Comments and Discussions

 
SuggestionHow to edit and delete the message once posted. And finally save entire chat as image. Pin
Rakesh Shah18-Nov-17 5:06
Rakesh Shah18-Nov-17 5:06 
QuestionHow to get buttons, images, videos and URLs specifically for a particular message/text in this code? Pin
Member 131725324-May-17 4:49
Member 131725324-May-17 4:49 
Bugerror Pin
Member 1316184629-Apr-17 19:49
Member 1316184629-Apr-17 19:49 
QuestionHello Pin
Member 1305327611-Mar-17 10:52
Member 1305327611-Mar-17 10:52 
AnswerRe: Hello Pin
JoCodes3-Apr-17 18:48
JoCodes3-Apr-17 18:48 
News[My vote of 1] bad this Pin
Member 128408696-Dec-16 0:04
Member 128408696-Dec-16 0:04 
QuestionHelp me to get reply message Pin
Member 1249588531-Jul-16 20:32
Member 1249588531-Jul-16 20:32 
AnswerRe: Help me to get reply message Pin
JoCodes11-Sep-16 6:40
JoCodes11-Sep-16 6:40 
Questionconnect Database Pin
Member 1257654310-Jun-16 1:32
Member 1257654310-Jun-16 1:32 
AnswerRe: connect Database Pin
JoCodes12-Jun-16 5:27
JoCodes12-Jun-16 5:27 
Currently it seems out of scope for this tip. But its easy , if you try an internet search which can help you with enormous number of tutorials on DB insert and retrieval using Sqlite.
Thanks.
QuestionAdding picture from a gallery or camera to chat bubble Pin
Member ATC26-May-16 9:52
Member ATC26-May-16 9:52 
AnswerRe: Adding picture from a gallery or camera to chat bubble Pin
JoCodes12-Jun-16 5:25
JoCodes12-Jun-16 5:25 
GeneralRe: Adding picture from a gallery or camera to chat bubble Pin
Member ATC12-Jun-16 21:17
Member ATC12-Jun-16 21:17 
GeneralRe: Adding picture from a gallery or camera to chat bubble Pin
JoCodes12-Jun-16 21:59
JoCodes12-Jun-16 21:59 
GeneralRe: Adding picture from a gallery or camera to chat bubble Pin
Member ATC13-Jun-16 2:05
Member ATC13-Jun-16 2:05 
Questionretrieving the data from database Pin
Member 1233750729-Feb-16 6:39
Member 1233750729-Feb-16 6:39 
QuestionHow do I display a single calendar date on top for a batch of messages from the same day? Pin
Member 964606319-Oct-15 15:23
Member 964606319-Oct-15 15:23 
AnswerRe: How do I display a single calendar date on top for a batch of messages from the same day? Pin
JoCodes16-Nov-15 18:43
JoCodes16-Nov-15 18:43 
QuestionUpdating a single row Pin
Tanya Visagie28-Sep-15 10:55
Tanya Visagie28-Sep-15 10:55 
AnswerRe: Updating a single row Pin
JoCodes16-Nov-15 18:41
JoCodes16-Nov-15 18:41 
QuestionRequirements for backend services Pin
Member 1140203313-Jul-15 5:11
Member 1140203313-Jul-15 5:11 
AnswerRe: Requirements for backend services Pin
JoCodes13-Jul-15 6:58
JoCodes13-Jul-15 6:58 
QuestionMy Vote of 5 Pin
Hajish R I22-Apr-15 9:48
Hajish R I22-Apr-15 9:48 
AnswerRe: My Vote of 5 Pin
JoCodes22-Apr-15 9:53
JoCodes22-Apr-15 9:53 
QuestionMy Vote of 5 Pin
Mekki Ahmedi20-Apr-15 20:34
Mekki Ahmedi20-Apr-15 20:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.