•准備工作
首先制作一張 .9 格式的聊天氣泡,參見我的這篇博客;
需要注意的是,制作完成后,應該將原始文件刪除,否則AS會分不清楚而報錯。
新建一個 Empty Activity,Java 和 XML 文件的命名分別為 MainActivity.java 和 activity_main.xml;
•編寫精美的聊天界面
首先編寫主界面,修改 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:orientation="vertical" android:padding="10dp" android:background="#d8e0e8"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/msg_recycler_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:orientation="horizontal"> <EditText android:id="@+id/input_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="Type message here" android:textAllCaps="false" android:maxLines="2" android:gravity="left"/> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send" android:textAllCaps="false" android:textSize="20sp"/> </LinearLayout> </LinearLayout>我們在主界面中放置了一個 RecyclerView 用於顯示聊天的消息內容;
又放置了一個 EditText 用於輸入消息,還放置了一個 Button 用於發送消息;
然后,定義消息的實體類,新建 Msg.java,代碼如下:
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"> <LinearLayout android:id="@+id/left_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" android:orientation="vertical" android:background="@drawable/message_left"> <TextView android:id="@+id/left_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" android:textColor="@color/black"/> </LinearLayout> <LinearLayout android:id="@+id/right_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:orientation="vertical" android:background="@drawable/message_left"> <TextView android:id="@+id/right_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" android:textColor="@color/black"/> </LinearLayout> </LinearLayout>這里我們讓收到的消息居左對齊,發出的消息居右對其;
並且使用 message_left.9 作為聊天氣泡;
接下來需要創建 RecyclerView 的適配器類,新建 MsgAdapter.java,添加代碼如下:
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder>{ private List<Msg> list; public MsgAdapter(List<Msg> list){ this.list = list; } static class ViewHolder extends RecyclerView.ViewHolder{ LinearLayout leftLayout; TextView left_msg; LinearLayout rightLayout; TextView right_msg; public ViewHolder(View view){ super(view); leftLayout = view.findViewById(R.id.left_layout); left_msg = view.findViewById(R.id.left_msg); rightLayout = view.findViewById(R.id.right_layout); right_msg = view.findViewById(R.id.right_msg); } } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Msg msg = list.get(position); if(msg.getType() == Msg.TYPE_RECEIVED){ //如果是收到的消息,則顯示左邊的消息布局,將右邊的消息布局隱藏 holder.leftLayout.setVisibility(View.VISIBLE); holder.left_msg.setText(msg.getContent()); //注意此處隱藏右面的消息布局用的是 View.GONE holder.rightLayout.setVisibility(View.GONE); }else if(msg.getType() == Msg.TYPE_SEND){ //如果是發出的消息,則顯示右邊的消息布局,將左邊的消息布局隱藏 holder.rightLayout.setVisibility(View.VISIBLE); holder.right_msg.setText(msg.getContent()); //同樣使用View.GONE holder.leftLayout.setVisibility(View.GONE); } } @Override public int getItemCount() { return list.size(); } }最后修改 MainActivity.java 中的代碼,來為 RecyclerView 初始化一些數據,並給發送按鈕加入事件響應;
代碼如下:
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private List<Msg> msgList = new ArrayList<>(); private RecyclerView msgRecyclerView; private EditText inputText; private Button send; private LinearLayoutManager layoutManager; private MsgAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msgRecyclerView = findViewById(R.id.msg_recycler_view); inputText = findViewById(R.id.input_text); send = findViewById(R.id.send); layoutManager = new LinearLayoutManager(this); adapter = new MsgAdapter(msgList = getData()); msgRecyclerView.setLayoutManager(layoutManager); msgRecyclerView.setAdapter(adapter); /* 我們還需要為button建立一個監聽器,我們需要將編輯框的內容發送到 RecyclerView 上: ①獲取內容,將需要發送的消息添加到 List 當中去。 ②調用適配器的notifyItemInserted方法,通知有新的數據加入了,趕緊將這個數據加到 RecyclerView 上面去。 ③調用RecyclerView的scrollToPosition方法,以保證一定可以看的到最后發出的一條消息。*/ send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = inputText.getText().toString(); if(!content.equals("")) { msgList.add(new Msg(content,Msg.TYPE_SEND)); adapter.notifyItemInserted(msgList.size()-1); msgRecyclerView.scrollToPosition(msgList.size()-1); inputText.setText("");//清空輸入框中的內容 } // 自定義一問一答 if(msgList.size() == 2){ msgList.add(new Msg("What's your name?",Msg.TYPE_RECEIVED)); adapter.notifyItemInserted(msgList.size()-1); msgRecyclerView.scrollToPosition(msgList.size()-1); } if(msgList.size() == 4){ msgList.add(new Msg("Nice to meet you,Bye!",Msg.TYPE_RECEIVED)); adapter.notifyItemInserted(msgList.size()-1); msgRecyclerView.scrollToPosition(msgList.size()-1); } } }); } private List<Msg> getData(){ List<Msg> list = new ArrayList<>(); list.add(new Msg("Hello",Msg.TYPE_RECEIVED)); return list; } }
•運行效果