先上效果图:
实现步骤:
1、首先编写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: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">
<EditText
android:id="@+id/input_text"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2"/>
<Button
android:id="@+id/send"
android:text="send"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
位于上方的RecyclerView的layout_height设置为1,占满除了按钮和输入框之外的全部空间
2、编写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="horizontal"
android:padding="0dp">
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
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="#fff" />
</LinearLayout>
<TextView
android:id="@+id/useless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_right">
<TextView
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="0dp" />
</LinearLayout>
</LinearLayout>
这里在left_layout和right_layout之间插入了一个id为useless的TextView,并将这个TextView的layout_weight设置为1,是为了让right_layout能够靠右对齐,因为在horizontal的LinearLayout中,layout_gravity设置为right也是无效的,所以只能用这种方法使得right_layout靠右对齐。
3、定义消息的实体类Msg,新建Msg类
package com.example.uibestpractice;
public class Msg {
public static final int TYPE_RECEIVED=0;
public static final int TYPE_SENT=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;
}
}
4、定义Msg类的适配器,新建类MsgAdapter
MsgAdapter继承了RecyclerView.Adapter<MsgAdapter.ViewHolder>,需要重写3个方法:onCreateViewHolder,onBindViewHolder,getItemCount
package com.example.uibestpractice;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {
private List<Msg> mMsgList;
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.left_layout);
rightLayout=(LinearLayout)view.findViewById(R.id.right_layout);
leftMsg=(TextView) view.findViewById(R.id.left_msg);
rightMsg=(TextView)view.findViewById(R.id.right_msg);
}
}
public MsgAdapter(List<Msg> msgList){
mMsgList=msgList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);//加载了msg_item布局
final ViewHolder holder=new ViewHolder(view);
holder.rightMsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position=holder.getAdapterPosition();//getAdapterPosition()返回点击数据在Adapter中的位置
Msg msg=mMsgList.get(position);
Toast.makeText(view.getContext(),"you clicked view"+msg.getContent(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder,int position){
Msg msg=mMsgList.get(position);
if(msg.getType()==Msg.TYPE_RECEIVED){//这里判断消息类型来决定由左边还是右边显示消息内容
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.INVISIBLE);
holder.leftMsg.setText(msg.getContent());
}
else if(msg.getType()==Msg.TYPE_SENT){
holder.rightLayout.setVisibility(View.VISIBLE);
holder.leftLayout.setVisibility(View.INVISIBLE);
holder.rightMsg.setText(msg.getContent());}
}
@Override
public int getItemCount(){
return mMsgList.size();
}
}
5、修改MainActivity的代码。
package com.example.uibestpractice;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Msg> msgList=new ArrayList<>();
private EditText inputText;
private Button send;
private RecyclerView msgRecyclerView;
private MsgAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMsgs();
inputText=(EditText)findViewById(R.id.input_text);
send=(Button)findViewById(R.id.send);
msgRecyclerView=(RecyclerView)findViewById(R.id.msg_recycler_view);
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
msgRecyclerView.addItemDecoration(new SpaceItemDecoration(50));//这里设置了RecyclerView子项的间隔
msgRecyclerView.setLayoutManager(layoutManager);
adapter=new MsgAdapter(msgList);
msgRecyclerView.setAdapter(adapter);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String content=inputText.getText().toString();
if(!"".equals(content)){//如果内容非空
Msg msg=new Msg(content,Msg.TYPE_SENT);
msgList.add(msg);
adapter.notifyItemInserted(msgList.size()-1);//调用适配器的notifyItemInserted()方法,用于通知适配器有新的数据插入
msgRecyclerView.scrollToPosition(msgList.size()-1);//将显示的数据定位到最后一行
inputText.setText("");
}
}
});
}
public void initMsgs(){
Msg msg1=new Msg("hello",Msg.TYPE_RECEIVED);
msgList.add(msg1);
Msg msg2=new Msg("hello.who is that",Msg.TYPE_SENT);
msgList.add(msg2);
}
class SpaceItemDecoration extends RecyclerView.ItemDecoration {
int mSpace;
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.left = 0;
outRect.right = 0;
outRect.bottom =0;
if (parent.getChildAdapterPosition(view) != 0) {
outRect.top = mSpace;
}
else{
outRect.top=0;
}
}
public SpaceItemDecoration(int space) {
this.mSpace = space;
}
}
}
其中定义了一个SpaceItemDecoration类,这个类继承自RecyclerView.ItemDecoration,重写其中的getItemOffsets后,就可以自己设置子项之间的间隔,单位为dp