Android学习笔记——RecyclerView编写气泡聊天
作者:互联网
声明
本次的代码部分参考郭霖——《第一行代码》,学习recyclerview章节后手动编写的。
.9图制作
.9图素材是本人用Windows附件中的画图工具制作的(就是找不到资源),然后导入Android Studio后进行编辑和引用。
- 气泡聊天背景的制作过程 在很多文章中有介绍,在此就不重复了。这里说一个我遇到的问题,在编辑时勾选了Show Content 和 Show Bad patches选项后,在图片中会报错红色区域。此时把左侧的拉伸区域限制到帧数较高的区域即可具体对比如下:
在我编辑的时候,图片中的红框怎么调都不会消失,也没有找到对应解决办法,偶然发现把左侧的黑线区域向下移动一下就可以了。//此处求大佬解释
Tip:在导入png格式图片到Android Studio中的时候要注意,图片的名字只能以a~z和0-9范围中的字符命名,否则图片会报错。
更改后的图如下:
此时.9图制作的差不多了,可以开始接下来的操作了。
布局代码编写
- 开始编写布局代码,此部分代码因为我迁移到了androidx,所以引用方式不同。 添加RecyclerView;
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/msg_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">
<Button
android:id="@+id/msg_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="S"
android:textSize="20sp"/>
<EditText
android:id="@+id/msg_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入"
android:maxLines="2"/>
<Button
android:id="@+id/msg_send"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="发送"
android:textSize="20sp"
android:background="#FF03DAC5"/>
</LinearLayout>
</LinearLayout>
2.再创建一个item布局来装载消息,注意在这一步中我不小心把最外层的layout_height的值设置成了match_parent,最后运行程序就成了一条消息占据了一个屏幕页,正确的值应该设置为wrap_content;
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/layout_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left">
<ImageView
android:id="@+id/image_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ai"/>
<TextView
android:id="@+id/msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/msgleft"
android:padding="10dp"
android:layout_gravity="center"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layout_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right">
<TextView
android:id="@+id/msg_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/msgright"
android:layout_gravity="right"
android:padding="10dp"/>
<ImageView
android:id="@+id/image_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/me"/>
</LinearLayout>
</LinearLayout>
代码部分
- 新建一个实体类,来区分消息类型;
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;
}
}
- 创建适配器,用于实现把要展示的数据源传进来,然后可以基于这些数据源进行操作,包括设置当消息类型为接收时隐藏右边的消息框,当消息为发送时,隐藏左边的对话框,在适配器里面,需要重写onCreatViewHolder()、onBindViewHolder()和getItemCoun()三个方法,在写适配器继承于RecyclerView.Adapter的时候系统会自动提醒你;
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {
private List<Msg>mMsgList;
static class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout leftLayout;
LinearLayout rightLayout;
ImageView leftImage;
ImageView rightImage;
TextView leftMsg;
TextView rightMsg;
public ViewHolder( View view) {
super(view);
leftLayout = view.findViewById(R.id.layout_left);
rightLayout = view.findViewById(R.id.layout_right);
leftImage = view.findViewById(R.id.image_left);
rightImage = view.findViewById(R.id.image_right);
leftMsg = view.findViewById(R.id.msg_left);
rightMsg = view.findViewById(R.id.msg_right);
}
}
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);
return new ViewHolder(view);
}
@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.GONE);
holder.leftMsg.setText(msg.getContent());
}else if (msg.getType() == Msg.TYPE_SEND){
//如果是发出的消息,则显示在右边的布局,隐藏左边的布局
holder.leftLayout.setVisibility(View.GONE);
holder.rightLayout.setVisibility(View.VISIBLE);
holder.rightMsg.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
}
- 编写主代码,这里主要时调用适配器的notifyItemInserted()方法,来通知列表有新的数据插入。还有scrollToPosition()用于定位到最后一行,这样才能显示最后一行的消息;
public class MainActivity extends AppCompatActivity {
private List<Msg>msgList = new ArrayList<>();
private EditText inputText;
private Button sendtext;
private Button sendvoice;
private RecyclerView msgRecycleView;
private MsgAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMsgs();
inputText = findViewById(R.id.msg_edit);
sendtext = findViewById(R.id.msg_send);
sendvoice = findViewById(R.id.msg_voice);
msgRecycleView = findViewById(R.id.msg_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
msgRecycleView.setLayoutManager(layoutManager);
adapter = new MsgAdapter(msgList);
msgRecycleView.setAdapter(adapter);
sendtext.setOnClickListener(v -> {
String content = inputText.getText().toString();
if(!"".equals(content)){
Msg msg = new Msg(content,Msg.TYPE_SEND);
msgList.add(msg);
adapter.notifyItemInserted(msgList.size() - 1);//当有消息时刷新RecycleView中的显示
msgRecycleView.scrollToPosition(msgList.size() - 1);//将RecycleView定位到最后一行
inputText.setText("");//最后清空输入框中的内容
}
});
}
private void initMsgs(){
Msg msg1 = new Msg("你好",Msg.TYPE_RECEIVED);
msgList.add(msg1);
Msg msg2 = new Msg("你好",Msg.TYPE_SEND);
msgList.add(msg2);
Msg msg3 = new Msg("很高兴认识你",Msg.TYPE_RECEIVED);
msgList.add(msg3);
}
}
最后有一个重要的东西,我的真机是MI10,我把.9图放到drawable和drawable-hdpi中都不能显示.9图的引用效果。最后看到一位博主的解决办法得到灵感,想到在安卓版本较高的情况下,需要把图片资源放到xxxhdpi后缀的资源包下才能被显示出来,这里同理,同时可以观察在drawable下面的mipmap的命名规则也是这样的。
第一次写文章,如果有错望大家指出,我会积极修正。
标签:private,id,msg,Msg,Android,view,RecyclerView,public,气泡 来源: https://blog.csdn.net/weixin_52341583/article/details/115670548