0%

Android开发 | RecyclerView 仿QQ聊天界面实现

前言:看了郭霖先生的著作《第一行代码-第二版》决定自己动手实现一个,该篇博客包含了APP制作的全部流程,RecyclerView 视频教程RecyclerView 基础使用教程

RecyclerView 仿QQ聊天界面实现

1. 效果图
1
2. 步骤
2.1 材料准备

​ 在这里分享一个好用到炸裂的图库阿里巴巴矢量图标库 ,先注册,才可以下载里面的图片,从上述的演示图中 我们需要四个图片

  1. 男生头像

  2. 女生头像

  3. 左聊天气泡

  4. 右聊天气泡

    都可以在阿里巴巴矢量图标库 找到 ,并下载在当前工程目录下的drawable文件夹下 PS:一定要是PNG格式

2.2 9图制作

​ 什么是9图? 其实9图是安卓开发当中常用的一种图片格式(.9.png) ,这种图片有一个特点就是 他可以规定图片在被拉伸时,那一部分区域是可以被拉伸的,那一部分是放内容的,记住:左上 拉伸,右下内容,如何将PNG图片 转为.9.png格式的图片,在AndroidStudio中 右击PNG 图片就可以看到,注意:在创作完.9图片以后 需要把原来的图片删掉,不然AS会资源重复错误(个人觉得是因为 AS认为.9图和原来的图是一个资源)

image-20210321163245580

image-20210321163049337
2.3 布局代码
  1. activity_main 布局

    • 效果图:image-20210321163837502

    • 嵌套布局:整体就是一个LinerLayout中包含了RecycleView与两个LinearLayout

      image-20210321163946521

    • 源码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      <?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:layout_margin="3dp"
      android:orientation="vertical">

      <androidx.recyclerview.widget.RecyclerView
      android:id="@+id/rv"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:layout_weight="18"/>
      <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:orientation="horizontal"
      android:layout_weight="1">
      <ImageView
      android:id="@+id/img_photo"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="8dp"
      android:src="@drawable/photo"/>
      <ImageView
      android:id="@+id/img_camera"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="8dp"
      android:src="@drawable/camera"/>
      <ImageView
      android:id="@+id/img_express"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:padding="8dp"
      android:layout_weight="1"
      android:src="@drawable/expression"/>
      <ImageView
      android:id="@+id/img_add"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="8dp"
      android:src="@drawable/add"/>

      </LinearLayout>
      <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:orientation="horizontal">

      <EditText
      android:id="@+id/edit"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="4"
      android:layout_marginLeft="5dp"
      android:hint="要发送的话"
      android:lines="2"/>
      <Button
      android:id="@+id/btn_send"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:text="发送" />
      </LinearLayout>



      </LinearLayout>
  2. RecycleView中item_layout布局

    • 效果图:

    • 布局格式:整体我们采用了RelativeLayout,又嵌套了两个LinearLayoutLinearLayout中又包含了 头像与 聊天框

      image-20210321164504456

    • 源码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:padding="10dp">

      <LinearLayout
      android:id="@+id/linear_left"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:orientation="horizontal">

      <ImageView
      android:id="@+id/head_left"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/boy_head" />

      <LinearLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginLeft="3dp"
      android:background="@drawable/left">


      <TextView
      android:id="@+id/msg_left"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center" />
      </LinearLayout>
      </LinearLayout>

      <LinearLayout
      android:id="@+id/linear_right"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_below="@+id/linear_left"
      android:layout_alignParentRight="true">




      <LinearLayout

      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginLeft="3dp"
      android:layout_toLeftOf="@+id/head_right"
      android:background="@drawable/right">

      <TextView
      android:id="@+id/msg_right"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center" />
      </LinearLayout>

      <ImageView
      android:id="@+id/head_right"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentRight="true"
      android:src="@drawable/girl_head" />
      </LinearLayout>


      </RelativeLayout>
2.4 后台代码(看不懂 就去看前言中 的视频)
  1. Message类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class Message {
    public static int TYPE_RECEIVE = 0;
    public static int TYPE_SEND = 1;
    private String content;
    private int type;

    public Message(String content, int type) {
    this.content = content;
    this.type = type;
    }

    public String getContent() {
    return content;
    }

    public void setContent(String content) {
    this.content = content;
    }

    public int getType() {
    return type;
    }

    public void setType(int type) {
    this.type = type;
    }
    }
  2. Adapter类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<Message> data;
    private Context context;

    public MyAdapter(List<Message> data, Context context) {
    this.data = data;
    this.context = context;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = View.inflate(context, R.layout.item_layout, null);
    return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
    Message message = data.get(position);
    if (message.getType() == Message.TYPE_RECEIVE) {
    holder.linear_left.setVisibility(View.VISIBLE);
    holder.linear_right.setVisibility(View.GONE);
    holder.left_text.setText(message.getContent());
    } else {
    holder.linear_left.setVisibility(View.GONE);
    holder.linear_right.setVisibility(View.VISIBLE);
    holder.right_text.setText(message.getContent());
    }

    }

    @Override
    public int getItemCount() {
    return data == null ? 0 : data.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
    private LinearLayout linear_left;
    private LinearLayout linear_right;
    private TextView left_text;
    private TextView right_text;

    public ViewHolder(@NonNull View itemView) {
    super(itemView);
    linear_left = itemView.findViewById(R.id.linear_left);
    linear_right = itemView.findViewById(R.id.linear_right);
    left_text = itemView.findViewById(R.id.msg_left);
    right_text = itemView.findViewById(R.id.msg_right);
    }
    }
    }
  3. activity_main 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    public class MainActivity extends AppCompatActivity {
    private EditText editText;
    private Button btn_send;
    private RecyclerView recyclerView;
    private ImageView img_add;
    private ImageView img_camera;
    private ImageView img_photo;
    private ImageView img_express;
    private MyAdapter adapter;
    private List<Message> data = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
    actionBar.hide();
    }
    bindView();
    init_data();
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(linearLayoutManager);

    adapter = new MyAdapter(data, this);
    recyclerView.setAdapter(adapter);

    btn_send.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    String s = editText.getText().toString();
    if (s.equals("") == false) {
    Message message = new Message(s, Message.TYPE_SEND);
    data.add(message);
    //当有新消息时,刷新RecyclerView
    adapter.notifyItemInserted(data.size() - 1);
    //将屏幕滚动到最新消息
    recyclerView.scrollToPosition(data.size() - 1);
    editText.setText("");

    } else {
    Toast.makeText(MainActivity.this, "发送消息不能为空!", Toast.LENGTH_SHORT).show();
    }
    }
    });

    }

    public void bindView() {
    editText = findViewById(R.id.edit);
    btn_send = findViewById(R.id.btn_send);
    recyclerView = findViewById(R.id.rv);
    img_add = findViewById(R.id.img_add);
    img_camera = findViewById(R.id.img_camera);
    img_express = findViewById(R.id.img_express);
    img_photo = findViewById(R.id.img_photo);
    }

    public void init_data() {
    Message meg1 = new Message("Hello, 我叫白文磊", Message.TYPE_RECEIVE);
    data.add(meg1);
    Message meg2 = new Message("Hello, 我叫郭涵博", Message.TYPE_SEND);
    data.add(meg2);
    }
    }
3. 源码分享