Android学习笔记——RecyclerView编写气泡聊天

声明

本次的代码部分参考郭霖——《第一行代码》,学习recyclerview章节后手动编写的。

.9图制作

.9图素材是本人用Windows附件中的画图工具制作的(就是找不到资源),然后导入Android Studio后进行编辑和引用。

  1. 气泡聊天背景的制作过程 在很多文章中有介绍,在此就不重复了。这里说一个我遇到的问题,在编辑时勾选了Show Content 和 Show Bad patches选项后,在图片中会报错红色区域。此时把左侧的拉伸区域限制到帧数较高的区域即可具体对比如下:
    在这里插入图片描述在我编辑的时候,图片中的红框怎么调都不会消失,也没有找到对应解决办法,偶然发现把左侧的黑线区域向下移动一下就可以了。//此处求大佬解释
    Tip:在导入png格式图片到Android Studio中的时候要注意,图片的名字只能以a~z和0-9范围中的字符命名,否则图片会报错。
    更改后的图如下:
    在这里插入图片描述此时.9图制作的差不多了,可以开始接下来的操作了。

布局代码编写

  1. 开始编写布局代码,此部分代码因为我迁移到了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>

代码部分

  1. 新建一个实体类,来区分消息类型;
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;
    }
}
  1. 创建适配器,用于实现把要展示的数据源传进来,然后可以基于这些数据源进行操作,包括设置当消息类型为接收时隐藏右边的消息框,当消息为发送时,隐藏左边的对话框,在适配器里面,需要重写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();
    }
}
  1. 编写主代码,这里主要时调用适配器的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的命名规则也是这样的。

第一次写文章,如果有错望大家指出,我会积极修正。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值