设计 Android 聊天气泡 (聊天 UI)
创建简单的 Android 聊天气泡或聊天 UI 布局
引言
在本技巧中,我们可以看到如何设计一个聊天气泡(简单来说就是一个聊天
UI)。
背景
如今,许多移动应用程序都具有聊天功能。 因此,在这里,我们快速讨论如何为自己设计一个。 我们将尽力保持简洁明了,以保持其简单性。
屏幕截图
Using the Code
我们需要使用 ListView
来显示聊天列表,listItem
来显示单个聊天消息,Adapter
来填充 ListView
,Model Class
来表示聊天消息,以及最重要的 - 9宫格图片。 对 9 宫格图片的简单解释是,它被设置为背景(气泡),并根据文本大小进行拉伸。 它的创建方式就是将任何 PNG 图像保存为 .9.png 扩展名格式。
首先,我们从创建一个 Activity
及其 Layout
文件开始,该文件代表我们的聊天 UI。
activity_chat.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
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);
}
}
}
列表项,显示单个聊天消息,此文本的背景将设置为聊天气泡(我们的 9 宫格图片)。
<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>
现在我们需要一个 Model 类来表示聊天消息,以及一个 Adapter
来填充 ListView
。
ChatMessage.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
像往常一样,我们使用 ViewHolder
模式来提高效率,在重新创建 Listview
中的每个项目时。 LayoutParams
用于根据聊天消息的发送或接收来设计左对齐或右对齐的布局。 一个虚拟布尔值用作属性,以检查它是发送还是接收,以简化操作。
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;
}
}
现在,我们完成设计聊天气泡的任务所需的一切都已准备就绪。 此示例是使用 Android Studio IDE 创建的。 我已发布完整的代码,可以下载。
关注点
该示例的设计目的是为了方便您自己尝试。 祝您编码愉快。 :) 如果您有任何疑问或疑问,请与我联系。
历史
- 2015 年 4 月 17 日:初始版本