编写精美的聊天界面(左边显示接收消息,右边显示发送消息)(项目已上传GitHub)
附上我的GitHub項目地址:
https://github.com/Skymqq/UIChat.git
?
學習Android開發,了解一個精美聊天界面的實現是很有必要的,如果可以掌握這個技能,那么在下次接觸聊天項目的時候,UI這方面你就有了些基礎經驗了,加油喲。
首先創建一個UIChat項目。
在實戰開始之前,我們還需要學習一下如何制作Nine-Patch圖片。你可能之前還沒有聽說過這個名詞,它是一種被特殊處理過的png圖片,能夠指定哪些區域可以被拉伸、哪些區域不可以。
那么Nine-Path圖片到底有什么實際作用呢?我們還是通過一個例子來看一下吧。比如項目中有一張氣泡樣式的圖片chat.png,如圖所示:
我們將這張圖片設置為LinearLayout的背景圖片,修改activity_main.xml中的代碼,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@mipmap/chat"></LinearLayout>效果圖:
我們看到,這個圖像被拉伸的很扭曲,非常難看。這個時候Nine-Patch圖片就可以用來改善程序的適配了。
這里我們只需要在資源目錄中找到圖片,并且右擊,選擇Create 9-Patch file...? 然后下一步,就生成了一個chat.9.png的圖片,我們打開它,并且將鼠標移動到灰色邊框旁邊,分別在4個方向上拖動鼠標,繪制出4個小黑邊,小黑邊就是允許拉伸的區域,具體步驟請看圖解:
?
?
這個時候有了兩張png圖片,將chat.png圖片刪除,我們就可以看到圖像已經適配了,至于為何background還是冒紅色,這個我就不太清楚了,至少我運行是沒有問題的
預覽界面:
運行效果圖:
這樣當圖片需要拉伸的時候,就可以只拉伸指定的區域,程序在外觀上也有了很大的改進,有了這個知識儲備之后,我們就可以進入實戰的環節了。
既然是要編寫一個聊天界面,那就肯定要有收到的消息和發出的消息。上面我們制作的chat.9.png可以作為收到消息的背景圖,這里為了區分左右,我們將chat.9.png改名為chat_left.9.png(改名的快捷鍵是shift+F6),接下來我們再像之前制作Nine-Patch圖片一樣,再制作一張chat_right.9.png圖片作為右邊發送消息的背景圖。
兩張背景圖準備就緒之后,我們就可以正式編碼了。由于我們等下會使用到RecyclerView控件,所以,我們需要在app/build.gradle當中添加依賴庫,如下所示:
implementation 'com.android.support:recyclerview-v7:28.0.0'activity_main.xml代碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#d8e0e8"android:orientation="vertical"><!--RecyclerView列表--><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><!--EditText輸入消息內容--><EditTextandroid:id="@+id/et_msg"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:hint="Type something here"android:maxLines="2" /><!--Button發送消息--><Buttonandroid:id="@+id/btn_send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="send"android:textAllCaps="false" /></LinearLayout></LinearLayout>預覽界面:
?
我們在主界面中放置了一個RecyclerView用于顯示聊天的消息內容,又放置了一個EditText用于輸入消息,還放置了一個Button用于發送消息。
然后定義一個消息的實體類,新建Msg類,代碼如下所示:
package com.example.administrator.uichat;public class Msg {public static final int TYPE_RECEIVED = 0;//靜態常量,用于表示消息類型為接收狀態public static final int TYPE_SEND = 1;//靜態常量,用于表示消息類型為發送狀態private String content;//消息內容private int type;//消息類型public Msg(String content, int type) {this.content = content;this.type = type;}public String getContent() {return content;}public int getType() {return type;} }Msg類中只有兩個字段,content表示消息的內容,type表示消息的類型。其中消息類型有兩個值可以選擇,TYPE_RECEIVED表示這是一條收到的消息,TYPE_SEND表示這是一條發出的消息。
接下來編寫,RecyclerView子項的布局,新建msg_item.xml,代碼如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:padding="10dp"><!--左邊,收到消息布局--><LinearLayoutandroid:id="@+id/linearLayout_left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="left"android:background="@mipmap/chat_left"><!--顯示文字設置--><TextViewandroid:id="@+id/tv_left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="10dp"android:textColor="#fff"android:textSize="15sp"android:textStyle="bold" /></LinearLayout><!--右邊,發送消息布局--><LinearLayoutandroid:id="@+id/linearLayout_right"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:background="@mipmap/chat_right"><!--顯示文字設置--><TextViewandroid:id="@+id/tv_right"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="10dp"android:textColor="#000"android:textSize="15sp"android:textStyle="bold" /></LinearLayout> </LinearLayout>預覽界面:
這里我們讓收到的消息居左對齊,發出的消息居右對齊,并且分別使用chat_left.9.png和chat_right.9.png作為背景圖。你可能會有些疑慮,怎么能讓收到的消息和發出的消息都放在同一個布局里呢?不用擔心,還記得我們之前學習過的可見屬性嗎?只要稍后在代碼中根據消息的類型來決定隱藏和顯示哪種消息就可以了。
接下來需要創建RecyclerView的適配器類,新建類MsgAdapter,代碼如下所示:
package com.example.administrator.uichat;import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView;import java.util.List;public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {private List<Msg> msgList;public MsgAdapter(List<Msg> msgList) {this.msgList = msgList;}static class ViewHolder extends RecyclerView.ViewHolder {LinearLayout leftLayout;LinearLayout rightLayout;TextView leftMsg;TextView rightMsg;public ViewHolder(View view) {super(view);leftLayout = (LinearLayout) view.findViewById(R.id.linearLayout_left);rightLayout = (LinearLayout) view.findViewById(R.id.linearLayout_right);leftMsg = (TextView) view.findViewById(R.id.tv_left);rightMsg = (TextView) view.findViewById(R.id.tv_right);}}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.msg_item, viewGroup, false);//加載子項布局return new ViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {Msg msg = msgList.get(i);//獲取List列表中的Msg實例if (msg.getType() == Msg.TYPE_RECEIVED) {//如果是收到的消息,則顯示左邊的消息布局,將右邊的消息布局隱藏viewHolder.leftLayout.setVisibility(View.VISIBLE);//顯示左邊消息布局viewHolder.rightLayout.setVisibility(View.GONE);//隱藏右邊消息布局,并且不占屏幕空間viewHolder.leftMsg.setText("" + msg.getContent());//將消息內容顯示} else if (msg.getType() == Msg.TYPE_SEND) {//如果是發出的消息,則顯示右邊的消息布局,將左邊的消息布局隱藏viewHolder.rightLayout.setVisibility(View.VISIBLE);//顯示右邊消息布局viewHolder.leftLayout.setVisibility(View.GONE);//隱藏左邊消息布局viewHolder.rightMsg.setText("" + msg.getContent());//將消息內容顯示}}@Overridepublic int getItemCount() {return msgList.size();}}這段代碼比較簡單,我也都基本上給了注釋,分析就略過了。
最后修改MainActivity.java代碼,來為RecyclerView初始化一些數據,并給發送按鈕加入事件響應,代碼如下所示:
package com.example.administrator.uichat;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Button; import android.widget.EditText;import java.util.ArrayList; import java.util.List;public class MainActivity extends AppCompatActivity {private List<Msg> msgList = new ArrayList<>();private EditText et_msg;private Button btn_send;private RecyclerView recyclerView;private MsgAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();//初始化UI控件initData();//初始化數據}private void initView() {et_msg = (EditText) findViewById(R.id.et_msg);btn_send = (Button) findViewById(R.id.btn_send);recyclerView = (RecyclerView) findViewById(R.id.recyclerView);}private void initData() {initMsg();//初始化消息LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);recyclerView.setLayoutManager(layoutManager);adapter = new MsgAdapter(msgList);recyclerView.setAdapter(adapter);}private void initMsg() {Msg msg1 = new Msg("Hello guy", Msg.TYPE_RECEIVED);msgList.add(msg1);Msg msg2 = new Msg("Hello Who is that?", Msg.TYPE_SEND);msgList.add(msg2);Msg msg3 = new Msg("This is Tom. Nice talking to you. ", Msg.TYPE_RECEIVED);msgList.add(msg3);}@Overrideprotected void onResume() {super.onResume();btn_send.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String content = et_msg.getText().toString();if (!"".equals(content)) {Msg msg = new Msg(content, Msg.TYPE_SEND);msgList.add(msg);adapter.notifyItemInserted(msgList.size() - 1);//當有消息時,刷新RecyclerView中的顯示recyclerView.scrollToPosition(msgList.size() - 1);//將RecyclerView定位到最后一行et_msg.setText("");//清空輸入框中的內容}}});}}其實看起來代碼量一點不多,我們具體劃分一下步驟,你可能就覺得實現思路賊easy了。
步驟1:聲名控件、聲名并初始化List<Msg>類型的集合,聲名適配器
步驟2:初始化控件
步驟3:初始化數據,這其中又可劃分為:1初始化消息,就是先自定義3個Msg實例放入List集合中,這就是運行程序時先顯示的3個消息的內容,2初始化適配器,3為RecyclerView控件設置LinearLayoutMannager(線性布局管理器,默認是垂直方向顯示的),為RecyclerView設置適配器。
步驟4:為Button按鈕設置點擊監聽,先判斷EdtiText中的內容是否為空,只有在EditText中的內容非空的時候,我們才能將消息內容和消息類型設置好,然后將消息實例放入List集合中,再將List集合作為參數傳入適配器中,最后刷新適配器,并且將消息定位到RecyclerView的最后一行,同時清除EditText控件中的內容。
?
如果你們可以根據代碼,可以很清晰地明白實現思路,其實沒必要看我的分析,我都感覺自己說的有點聒噪了...
畢竟,看代碼,有自己獨特的見解才是最好的。
最終效果圖:
?
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的编写精美的聊天界面(左边显示接收消息,右边显示发送消息)(项目已上传GitHub)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人生意外险是什么
- 下一篇: Fragment碎片的基本使用(手机平板