类微信界面AS开发(二)——RecyclerView的简单实现

2,623 阅读5分钟

ps:拖延症晚期...拖到现在才写,我是废物

OK,废话不多说,继续我们的实验,上次做完整体界面的布局后,这次开始对界面实现RecyclerView。(就类似于微信界面的滚动)

一:什么是RecyclerView

官方解释如下:

A flexible view for providing a limited window into a large data set.

意思就是说在一个有限的窗口中显示大量的数据集。

回顾一下以前我们使用的ListView ListView的局限

  1. 只有纵向列表一种布局

  2. 没有支持动画的API

  3. 接口设计和系统不一致 setOnItemClickListener() setOnItemLongClickListener() setSelection()

  4. 没有强制实现ViewHolder

  5. 性能不如RecyclerView

下面我们看看RecyclerView的几个重要组件:

二:RecyclerView的基本使用

在使用RecyclerView时候,必须指定一个适配器Adapter和一个布局管理器LayoutManager

我们这样思考,当我们去完成一个界面的布局时,我们要向里面传数据,怎么去传呢?全写在xml文件里显而不合适,这就是Adapter的作用。

简而言之,Adapter就是数据与ui之间的桥梁,它把数据与前端ui连接到一起,是一个展示数据的载体。

而设置布局管理器RecyclerView则是来控制Item的布局方式,横向、竖向以及瀑布流方式

例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还StaggeredGridLayoutManager等)。也就是说RecyclerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。

下面我们展示RecyclerView的基本使用方法:

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
LinearLayoutManager layoutManager = new LinearLayoutManager(this );  
//设置布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//设置为垂直布局,这也是默认的  
layoutManager.setOrientation(OrientationHelper. VERTICAL);  
//设置Adapter  
recyclerView.setAdapter(recycleAdapter);  
 //设置分隔线  
recyclerView.addItemDecoration( new DividerGridItemDecoration(this ));  
//设置增加或删除条目的动画  
recyclerView.setItemAnimator( new DefaultItemAnimator());  

现在我们了解了什么是RecyclerView,RecyclerView的作用是什么,RecyclerView的基本使用,下面,我们正式开始对上次的实验进行完善。

三:修改原有xml文件

为了实现RecyclerView,我们将初始的xml文件修改为ConstrainLayout(约束布局)并添加RecyclerView。 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/tab02_RecyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_margin="8dp"
        android:overScrollMode="never"
        android:scrollbars="none" />

现在,我们已经有了一个RecycleView的视图,接下来,我们要向里面添加东西。

四:创建RecyclerView的item.xml

当我们创建好RecyclerView时,我们思考,我们现在拥有的不管是一片空白。

我们把RecycleView视为一个大的集装箱,现在大的集装箱需要向里面添加一个个模式固定的小盒子,而小盒子里存放的就是我们的数据。

那么我们现在需要做的就是创建这个小盒子的xml文件。

先看完示意图应该会便于理解:

可以看到,灰色部分就是我们创建的“小盒子”, 这个小盒子RecyclerView的基本单位。里面存放的数据的数据结构都是一样的。

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="8dp"
    android:background="@android:color/darker_gray"
    android:orientation="vertical">

    <TextView
        android:id="@+id/item02_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        tools:text="1" />

    <TextView
        android:id="@+id/item02_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        tools:text="内容" />

</LinearLayout>

RecyclerView与item的xml代码其实都不难理解,真正的重点在我们接下来要讲的东西。

五:修改Fragment文件

在上一步,我们已经造好了存放数据的“小盒子”。但是盒子里什么都没有啊,没有数据啊。

这时候就需要修改之前的Fragment文件,在Fragment里创建List,然后再调用Adapter将List里的数据传入到“小盒子”。 (*注意!不是MainActivity*)

MainActivity只是起的更多的是一个整体的调动作用(也就是页面的切换)

而每个界面自己的控制,数据输入等则是它自己的Fragment。

老样子,首先在Fragment里进行声明:

    // 添加存储数据的列表
    private List<String> mList = new ArrayList<>();
    private Context context;
    private RecyclerView recyclerView;
    private VerticalAdapter verticalAdapter;

然后修改onCrete函数,onCreate函数起到的作用可以看作是对界面的初始化。

在这里,我们对view、context、adapter、LinearLayoutManager以及list赋值。

代码如下:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        View view = inflater.inflate(R.layout.tab02, container, false);
        context = view.getContext();
        recyclerView = view.findViewById(R.id.tab02_RecyclerView);
        initData();
        LinearLayoutManager manager = new LinearLayoutManager(context);
        manager.setOrientation(LinearLayoutManager.VERTICAL);

        verticalAdapter = new VerticalAdapter(mList,context);

        recyclerView.setAdapter(verticalAdapter);
        recyclerView.setLayoutManager(manager);

        return view;
    }
    
    private void initData() {
    	//向list里添加数据
        mList.add("亚特兰大老鹰");
        mList.add("夏洛特黄蜂");
        mList.add("迈阿密热火");
        mList.add("奥兰多魔术");
        mList.add("华盛顿奇才");
        mList.add("波士顿凯尔特人");
        mList.add("布鲁克林篮网");
        mList.add("纽约尼克斯");
        mList.add("费城76人");
        mList.add("多伦多猛龙");
        mList.add("芝加哥公牛");
        mList.add("克里夫兰骑士");
        mList.add("底特律活塞");
    }

因为我们的Adapter是需要自己创建的,因此,我们新建一个java类,继承RecyclerView.Adapter。

六:创建自定义Adapter

在这里,我们通过构造函数对list与context赋值。

然后,重载函数:

  1. onCreateViewHolder(ViewGroup parent, int viewType) 方法。

     这个方法用于加载 RecyclerView 子项的布局,然后返回一个 ViewHolder 对象,ViewHolder  是一个静态内部类,继承自 RecyclerView.ViewHolder 类。
    
  2. onBindViewHolder(ViewHolder viewHolder, int i) 方法。

    上面那个方法为子项加载布局,这个方法为子项绑定数据。调用这两个方法后,子项就既有了布局又有了数据。
    
  3. getItemCount() 方法。

     用于获取 RecyclerView 一共有多少子项。
    

在这里,补充一个知识点,关于RecyclerView的调用顺序总是按照:

获取大小——>绑定布局——>加载ViewHolder类——>绑定数据

这样一个规律的,通过这样的规律,我们就能知道是按照怎样的顺序来调用这些重载函数的了。

代码如下:

package com.example.likewechat;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class VerticalAdapter extends RecyclerView.Adapter<VerticalAdapter.VerticalViewHolder> {

    private Context mContext;

    private List<String> mList;

    public VerticalAdapter(List<String> list, Context context) {
        mList = list;
        mContext = context;
    }


    @NonNull
    @Override
    public VerticalAdapter.VerticalViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(this.mContext).inflate(R.layout.item02, parent, false);
        return new VerticalViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull VerticalViewHolder holder, int position) {
        holder.tvNum.setText(position + 1 + "");
        holder.tvContent.setText(mList.get(position));
    }

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

    public static class VerticalViewHolder extends RecyclerView.ViewHolder {

        TextView tvNum, tvContent;

        public VerticalViewHolder(View itemView) {
            super(itemView);
            tvNum = itemView.findViewById(R.id.item02_num);
            tvContent = itemView.findViewById(R.id.item02_content);
        }
    }
}

七:结果展示

八:关于Adapter的总结

每当 RecyclerView 的子项出现在屏幕上时或将要出现在屏幕上时,系统会按照如下的顺序调用函数。

  1. 调用 getItemCount() 方法获取子项的数量。

  2. 调用 onCreateViewHolder(ViewGroup parent, int viewType) 方法加载每一个子项的布局

  3. 构造一个 ViewHolder 对象。

  4. 调用 onBindViewHolder(ViewHolder viewHolder, int i) 方法将数据绑定在 ViewHolder 对象中。

探究 RecyclerView 适配器重载函数的调用顺序就完成了,还要提醒一下的就是,当所有子项加载完后,移出屏幕的子项再次回到屏幕中时,是不会再次构造 ViewHolder 对象的,也就是说这个对象已经被构造过了,再次出现在屏幕中只需要复用就可以了。

参考博客: 探究RecyclerView适配器中重载函数的作用以及调用顺序

Android 控件 RecyclerView

Gitee源码:gitee.com/White-9/Lik…