•准备工作
首先制作一张 .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; } }
•运行效果