一、前言

<font face = 黑体>能够这样说,RecyclerView 的问世,代替了 ListView 和 GridView。RecyclerView 异样的灵便可自定义并可反复利用的 Item高度的解耦,并且通过设置不同的 LayoutManager、ItemDecoration 和 ItemAnimator 能够实现令人瞠目的成果。

<font face = 黑体>ItemDecoration 的相干解说大家能够看 这篇文章。

<font face = 黑体>源码曾经上传至 github,地址在文末中曾经给出,能够先下载到本地运行起来,因为具体事例解说的时候并没有把全副的代码贴出来。

二、与 RecyclerView 配合的类

  • <font face = 黑体>LayoutManager:布局管理器,治理 RecyclerView 的展现款式,零碎提供了列表、网格和瀑布流三种模式的布局管理器。
  • <font face = 黑体>Adapter:适配器,用来解决视图与数据之间的关系。
  • <font face = 黑体>ViewHolder:用来包容 View 视图。

三、案例介绍

<font face = 黑体>咱们要实现的最终成果如下所示:

<font face = 黑体>能够看到界面中有四个按钮,别离是增加数据、切换布局,插入一条数据和删除一条数据。当点击增加数据的时候,RecyclerView 就会以线性布局的形式展现出数据,当点击切换布局的时候,RecyclerView 会先切换成网格布局,而后再切换成瀑布流布局,当点击插入和删除数据的时候,RecyclerView 会依据默认的动画来执行,并且动静更新 ItemView 的 position。



四、实现线性布局列表

4.1、引入 RecyclerView

<font face = 黑体>要应用 RecyclerView,首先咱们须要在 app 的 build.gradle 中引入 RecyclerView 库。

implementation 'androidx.recyclerview:recyclerview:1.1.0'

4.2、创立适配器

<font face = 黑体>想要把数据展现在列表视图中,就须要通过适配器,所以咱们这里创立 MyRecyclerViewAdapter 继承自 RecyclerView 的 Adapter,并实现其中的三个办法,这里咱们以内部类的形式来实现 MyViewHolder,同样是继承自 RecyclerView 的 ViewHolder,具体代码如下所示:(源码文末给出)

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {    private Context mContext;    private List<String> dataSource;    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {        this.onItemClickListener = onItemClickListener;    }    public MyRecyclerViewAdapter(Context mContext) {        this.mContext = mContext;        this.dataSource = new ArrayList<>();    }    public void setDataSource(List<String> dataSource) {        this.dataSource = dataSource;        notifyDataSetChanged();    }    /**     * 创立并且返回 ViewHolder     *     * @param parent     * @param viewType     * @return     */    @NonNull    @Override    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {        return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false));    }    /**     * 通过 ViewHolder 来绑定数据     *     * @param holder     * @param position     */    @Override    public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {        holder.mIv.setImageResource(getIcon(position));        holder.mTv.setText(dataSource.get(position));    }    /**     * 返回数据数量     *     * @return     */    @Override    public int getItemCount() {        return dataSource.size();    }    // 获取图片    private int getIcon(int position) {        switch (position % 5) {            case 0:                return R.drawable.a;            case 1:                return R.drawable.b;            case 2:                return R.drawable.c;            case 3:                return R.drawable.d;            case 4:                return R.drawable.e;        }        return 0;    }    class MyViewHolder extends RecyclerView.ViewHolder {        private ImageView mIv;        private TextView mTv;        private View mItemView;        public MyViewHolder(@NonNull View itemView) {            super(itemView);            mIv = itemView.findViewById(R.id.iv);            mTv = itemView.findViewById(R.id.tv);            mItemView = itemView;        }    }}

4.3、在 MainActivity 应用适配器

<font face = 黑体>在 MainActivity 中实例化 Adapter,掉用 RecyclerView .setAdapter() 办法来显示数据,当点击增加数据的时候,就将模仿数据通过 setDataSource() 办法设置过来,在该办法中咱们写了 notifyDataSetChanged() 办法,所以,数据设置完后会告诉界面展现。

public class MainActivity extends AppCompatActivity {    private RecyclerView mRecyclerView;    private MyRecyclerViewAdapter mAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mRecyclerView = findViewById(R.id.recycler_view);        // 线性布局        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);        mRecyclerView.setLayoutManager(linearLayoutManager);        mAdapter = new MyRecyclerViewAdapter(this, mRecyclerView);        mRecyclerView.setAdapter(mAdapter);    }    /**     * 增加数据     * @param v     */    public void onAddDataClick(View v) {        List<String> data = new ArrayList<>();        for (int i = 0; i < 20; i++) {            String s = "第" + i + "条数据";            data.add(s);        }        mAdapter.setDataSource(data);    }}

4.4、成果展现

<font face = 黑体>具体成果如下所示:


五、切换布局

5.1、网格布局

<font face = 黑体>RecyclerView 的布局是通过 LayoutManager 来设置的,应用网格布局只须要实例化 GridLayoutManager,并调用RecyclerView.setLayoutManager() 办法就能够了, 以下代码中的 2 的意思是每一行都有两列数据。

public void onChangeLayoutClick(View v) {    // 网格布局    if (mRecyclerView.getLayoutManager().getClass() == LinearLayoutManager.class) {        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);        mRecyclerView.setLayoutManager(gridLayoutManager);    }}

5.2、瀑布流布局

<font face = 黑体>所谓瀑布流布局就是指 ItemView 的宽度雷同,然而高度不同。同样,咱们只须要实例化 StaggeredGridLayoutManager 并设置到 RecyclerView 外面去就能够了。

public void onChangeLayoutClick(View v) {    // 网格布局    if (mRecyclerView.getLayoutManager().getClass() == LinearLayoutManager.class) {        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);        mRecyclerView.setLayoutManager(gridLayoutManager);    }    // 瀑布流布局    else if (mRecyclerView.getLayoutManager().getClass() == GridLayoutManager.class) {        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);        mRecyclerView.setLayoutManager(staggeredGridLayoutManager);    }    // 线性布局    else if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);        mRecyclerView.setLayoutManager(linearLayoutManager);    }}

<font face = 黑体>这里为了模仿不同高度,所以咱们在Adapter中写了一个返回随机高度的办法,并且在 onBindViewHolder() 办法中判断以后应用的布局是不是瀑布流布局,如果是的话,就应用随机高度。

private int getRandomHeight() {    return (int) (Math.random() * 1000);}
@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {    holder.mIv.setImageResource(getIcon(position));    holder.mTv.setText(dataSource.get(position));    /**     * 只在瀑布流布局中应用随机高度     */    if (mRecyclerView.getLayoutManager().getClass() == StaggeredGridLayoutManager.class) {        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getRandomHeight());        holder.mTv.setLayoutParams(params);    } else {        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);        holder.mTv.setLayoutParams(params);    }}

5.3、成果展现

<font face = 黑体>具体成果如下所示:


六、插入数据与删除数据

<font face = 黑体>咱们在 Adapter 中定义如下增加数据和删除数据的办法,而后在 MainActivity 中调用就能够了,RecyclerView 的增加数据和删除数据会应用默认的动画,当然你也能够自定义动画。这里须要特地留神的是,当增加删除完数据后,肯定要调用 notifyItemRangeChanged() 这个办法,去刷新 ItemView,这个办法的第一个参数的意思是刷新的终点,第二个参数是刷新的数量。

/** * 增加一条数据 * @param position */public void addData(int position) {    addDataPosition = position;    dataSource.add(position, "插入的数据");    notifyItemInserted(position);    notifyItemRangeChanged(position, dataSource.size() - position);}/** * 删除一条数据 * @param position */public void removeData(int position) {    addDataPosition = -1;    dataSource.remove(position);    notifyItemRemoved(position);    notifyItemRangeChanged(position, dataSource.size() - position);}

6.1、成果展现

<font face = 黑体>具体成果如下所示:


七、小结

<font face = 黑体>这篇文章基本上曾经将 RecyclerView 的根本应用都讲完了,RecyclerView 的作用是在无限的显示空间外面去展现大量的数据,RecyclerView 自身只负责回收和复用 View,它须要与其余类的配合来达到展现数据的成果,比如说通过配合 Adapter 适配器来把视图与数据连接起来,通过配合 LayoutManager 来确定数据的展现模式(线性、网格、瀑布流),另外 RecyclerView 并没有提供 Item的点击事件响应办法,这个须要咱们本人去实现,源码中我曾经实现了这个办法,因为比较简单所以上述就没有讲了。

八、源码

<font face = 黑体>源码曾经上传至 github,大家间接下载就能够了。