In this post, I will provide a simple example that making this layout through using 9-patch images and
ListView
.Designing bubble layout
You can create the 9-patch images from them by using
draw9patch
tool in Android SDK. Let go to [YOUR_SDK_PATH]\sdk\tools
folder and open Command Prompt (in Windows) or Terminal (in Mac, Linux) and type this command:
draw9patch
You will see this dialog box:
Dragging your bubble images to it, custom some details and saving it, you'll have new 9-patch images after done:
|
|
Sample project code
drawable
folder and start coding!Design two layouts based on message type first:
item_chat_right.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@drawable/bubble_out"
android:orientation="vertical"
android:paddingBottom="10dp">
<TextView
android:id="@+id/txt_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="100dp"
android:padding="5dp"
android:textColor="@android:color/holo_green_dark" />
</LinearLayout>
</RelativeLayout>
item_chat_left.xml
Create a POJO (chat message) for the project:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="@drawable/bubble_in"
android:orientation="vertical"
android:paddingBottom="10dp">
<TextView
android:id="@+id/txt_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="100dp"
android:padding="5dp"
android:textColor="@android:color/holo_red_dark" />
</LinearLayout>
</RelativeLayout>
ChatMessage.java
The nature of the chat messages list is package info.devexchanges.chatbubble;
public class ChatMessage {
private String content;
private boolean isMine;
public ChatMessage(String content, boolean isMine) {
this.content = content;
this.isMine = isMine;
}
public String getContent() {
return content;
}
public boolean isMine() {
return isMine;
}
}
ListView
with odd/even row based on in or out message. Creating a ListView
adapter with this design style, never forget to override getViewTypeCount()
and getItemViewType()
in code:
MessageAdapter.java
Simple package info.devexchanges.chatbubble;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
public class MessageAdapter extends ArrayAdapter<ChatMessage> {
private Activity activity;
private List<ChatMessage> messages;
public MessageAdapter(Activity context, int resource, List<ChatMessage> objects) {
super(context, resource, objects);
this.activity = context;
this.messages = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
int layoutResource = 0; // determined by view type
ChatMessage chatMessage = getItem(position);
int viewType = getItemViewType(position);
if (chatMessage.isMine()) {
layoutResource = R.layout.item_chat_left;
} else {
layoutResource = R.layout.item_chat_right;
}
if (convertView != null) {
holder = (ViewHolder) convertView.getTag();
} else {
convertView = inflater.inflate(layoutResource, parent, false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
//set message content
holder.msg.setText(chatMessage.getContent());
return convertView;
}
@Override
public int getViewTypeCount() {
// return the total number of view types. this value should never change
// at runtime
return 2;
}
@Override
public int getItemViewType(int position) {
// return a value between 0 and (getViewTypeCount - 1)
return position % 2;
}
private class ViewHolder {
private TextView msg;
public ViewHolder(View v) {
msg = (TextView) v.findViewById(R.id.txt_msg);
}
}
}
Activity
to run, there is no special point here:
MainActivity.java
And it's layout:
package info.devexchanges.chatbubble;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private View btnSend;
private EditText editText;
boolean isMine = true;
private List<ChatMessage> chatMessages;
private ArrayAdapter<ChatMessage> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chatMessages = new ArrayList<>();
listView = (ListView) findViewById(R.id.list_msg);
btnSend = findViewById(R.id.btn_chat_send);
editText = (EditText) findViewById(R.id.msg_type);
//set ListView adapter first
adapter = new MessageAdapter(this, R.layout.item_chat_left, chatMessages);
listView.setAdapter(adapter);
//event for button SEND
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (editText.getText().toString().trim().equals("")) {
Toast.makeText(MainActivity.this, "Please input some text...", Toast.LENGTH_SHORT).show();
} else {
//add message to list
ChatMessage chatMessage = new ChatMessage(editText.getText().toString(), isMine);
chatMessages.add(chatMessage);
adapter.notifyDataSetChanged();
editText.setText("");
if (isMine) {
isMine = false;
} else {
isMine = true;
}
}
}
});
}
}
activity_main.xml
Running application, you will have this result:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/activity_horizontal_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.9">
<ListView
android:id="@+id/list_msg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/activity_horizontal_margin"
android:divider="@null"
android:listSelector="@android:color/transparent"
android:transcriptMode="alwaysScroll" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.1"
android:orientation="horizontal">
<EditText
android:id="@+id/msg_type"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.7"
android:hint="Input message" />
<Button
android:id="@+id/btn_chat_send"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:background="@color/background_floating_material_dark"
android:text="Send"
android:textColor="@color/background_material_light" />
</LinearLayout>
</LinearLayout>
Conclusions
ListView
widget, you can create the UI easily. Visit my @Github to get this full project code.
Update: thank you, my all visitors! This is one of the most viewed posts on my blog. Some readers has asked me about making a "real" chat application, not only bubble UI. Please read my newer post about creating a simple chat app using Firebase to find out the solution!