记一次RecyclerView的使用

一、前文

  说起来,RecyclerView使用也不是一时半会了,之前在使用RecyclerView的时候都是直接使用的  https://www.jianshu.com/p/b343fcff51b0 这个框架的 , 时间久了原生的RecyclerView反而感觉变的有些生疏, 刚好最近有些时间便想好好理理RecyclerView的原生基础使用 .


  如需转载请务必标明出处,谢谢 !!!

  **** 能力有限, 如有错误还望指点...****


 

二、简述

  因为, 这只是一篇学习中的随笔而并非什么科普文, 这里就不详细介绍RecyclerView的过人之处以及相比ListView或者GridView的优缺点了, 这里就只记录一下这次简单的RecyclerView的使用流程.

1、配置

  因为RecyclerView并非系统自带基础组件,这里是需要去添加依赖来使用的.

  在app的gradle文件中添加一下依赖

  

implementation 'com.android.support:recyclerview-v7:28.0.0-alpha3'

  * 这里解释一下 implementation 与 compile 的区别 :

    在新版本 Android Gradle plugin 3.0 中,已经将compile标记为废弃,更改为了implementation 和 api 两个,其中 api的功能和compile其等同的,而implementation添加的依赖只对当前的Module有效

2、使用

  首先布局中使用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="match_parent"
    android:orientation="vertical"
    android:background="@color/colorPrimary"
    tools:context="com.fordream.learnmvp.recyclerview.activity.RVTActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_rvt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:layout_margin="10dp"
            android:padding="10dp"
            android:text="添加数据"
            android:textSize="16sp"
            />
    </LinearLayout>
  
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_rvt"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none"
        />
</LinearLayout>

  这里我们在布局当中放置了TextView方便点击之后给RecyclerView添加数据使用 。

  在Activity中使用RecyclerView

  (这里在做RecyclerView练习的时候,同时也顺便练习了一下MVP的使用,所以下面的代码就只复制关键代码,不全部复制了)

  

     adapter = new RVTAdapter(RVTActivity.this, beans);
        recyclerView = findViewById(R.id.rv_rvt);
        recyclerView.setLayoutManager(new LinearLayoutManager(RVTActivity.this));
        recyclerView.setAdapter(adapter);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new DividerItemDecoration(RVTActivity.this, DividerItemDecoration.HORIZONTAL));

  可以看到在使用RecyclerView的时候在findViewById()之后我们需要进行一下配置:
  1、setLayoutManager() // 设置布局管理,也就是布局的样式 我们这里选择的是最常见的 纵向列表的样式  ( 我们还可以设置成网格样式或者瀑布流样式 )

  2、setAdapter() //和ListView一样设置适配器 ( 具体的适配器见下文 ) 

  3、setItemAnimator() // 设置列表中插入或删除数据时item的动画效果( 无这方面的需求可不配置该项 )

  4、setItemDecoration() //设置分割线 

  设置完这些RecyclerView便算是配置完了,接下来我们看看RecyclerView的Adapter的样式

  RecyclerView的Adapter

  首先咱们先看一下Item的布局

  

<?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="wrap_content"
    android:background="@color/colorPrimaryDark"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    >
    <ImageView
        android:id="@+id/iv_rvt_item"
        android:layout_width="60dp"
        android:layout_height="60dp"/>
    <TextView
        android:id="@+id/tv_rvt_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dp"
        android:textSize="14sp"
        />
</LinearLayout>

  我们在Item中放了一个图片和一段文字( 没有什么意义,仅仅为了展示 )

  我们在看Adapter的代码

  

public class RVTAdapter extends RecyclerView.Adapter<RVTAdapter.MyViewHolder> {

    private Context context;
    private List<RVTBean> beans;
    private RVTClickListener listener;

    public RVTAdapter(Context context, List<RVTBean> beans) {
        this.context = context;
        this.beans = beans;
    }

    public void setOnClickListener(RVTClickListener onClickListener) {
        this.listener = onClickListener;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_rvt, viewGroup, false));
        return holder;
    }

    public void addDates(List<RVTBean> rvtBeans) {
        beans.addAll(rvtBeans);
        notifyDataSetChanged();
    }

    public void addDate(RVTBean rvtBean, int position) {
        beans.add(position, rvtBean);
        notifyItemInserted(position);
        //notifyItemRangeChanged(position, beans.size() - position);
    }

    public void deleteDate(int position) {
        
        beans.remove(position);
        notifyItemRemoved(position);
        //notifyItemRangeChanged(position, beans.size() - position);
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int i) {
        myViewHolder.tv_name.setText(beans.get(i).getName());
        myViewHolder.iv_img.setImageResource(beans.get(i).getImg());

        if (listener != null) {

            myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    listener.itemOnClickListener(myViewHolder.itemView, myViewHolder.getLayoutPosition());
                }
            });

            myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    listener.itemOnLongClickListener(myViewHolder.itemView, myViewHolder.getAdapterPosition());
                    return false;
                }
            });

        }

    }

    @Override
    public int getItemCount() {
        return beans.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        private ImageView iv_img;
        private TextView tv_name;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            iv_img = itemView.findViewById(R.id.iv_rvt_item);
            tv_name = itemView.findViewById(R.id.tv_rvt_item);
        }
    }

}

  看似代码不少,其实按顺序来并不难,我们一点一点的看

  首先我们创建一个Adapter并让其继承 RecyclerView.Adapter , 此时先不慌解决编译器提示的错误 , 我们先在Adapter类中创建一个内部类 MyViewHolder 并继承自 RecyclerView.ViewHolder 

  然后我们在 RecyclerView.Adapter 之后增添我们刚刚创建的MyViewHolder作为泛型, 即: RecyclerView.Adapter<RVTAdapter.MyViewHolder>

  到了这里我们便可以根绝编译器的提示来实现RecyclerView.Adapter内的抽象方法, 分别是 onCreateViewHolder() 、onBindViewHolder()、 getItemCount() 这三个方法

  其中在onCreateViewHolder()中顾名思义就是创建ViewHolder ; 在onBindViewHolder()中顾名思义就是绑定数据即为ViewHolder中的布局各组件赋值、设置监听事件等 ; getItemCount() 就是获取数据集合的长度。

  在上面代码中,我们看到在我们这里在Adapter的构造方法中我们获取了当前的上下文以及数据集,同时我们添加了setOnClickListener()、addDate()、addDates()、deleteDate()这几个方法,也就是我们根据业务来处理业务的方法。

  我们主要是为了实现增加更多数据、插入单条数据、删除数据 , 同时我们对外做了接口的回调来处理Item的单击以及长按事件。

  

  当我们在Activity中点击"加载更多"时我们会调用adapter的addDates()方法, 来更改数据集并且做了刷新显示; 当我们单击某一条Item的时候我们会调用addDate()方法在点击的Item处插入一条新的数据,并作数据刷新处理 ; 当我们长按一条Item的时候我们会弹出提示框是否删除该Item, 确定之后执行Adapter的deleteDate()方法来删除该Item并刷新。

  我们来看一下Activity中相关代码:
  

adapter.setOnClickListener(new RVTClickListener() {
            @Override
            public void itemOnClickListener(View view, int position) {
                Toast.makeText(RVTActivity.this, "第" + position + "条", Toast.LENGTH_SHORT).show();
                rvtPersenterImp.addDate(position);//插入一条数据
            }

            @Override
            public void itemOnLongClickListener(View view, final int position) {
                final AlertDialog.Builder builder = new AlertDialog.Builder(RVTActivity.this);
                builder.setTitle("是否删除该条数据?")
                        .setMessage("第" + position + "条")
                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                            }
                        })
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                                rvtPersenterImp.deleteDate(position);//删除一条数据
                            }
                        })
                        .show();
            }
        });

        tv_addMore = findViewById(R.id.tv_rvt);
        tv_addMore.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rvtPersenterImp.loadMore();//加载更多
            }
        });

  **大家请自动屏蔽MVP有关的rvtPersenterImp**

  这里有一个自己踩的坑顺便提一下( 很low的错误,主要是不细心 )

  在删除数据时因为使用了Dialog进行提醒,所以在执行rvtPersenterImp.deleteDate()时需要一个int的参数,当时想也没想直接传入了 onClick()中的参数 int i , 结果每次执行删除都会报数组越界的异常, 当时在网上一顿的搜, 大部分都说是RecyclerView本身的一个BUG在删除数据时会导致数据错乱,是因为RecyclerView删除之后只是做了删除的效果,数据集并没有真正的改变, 同时网友也给出了具体的避免方法( 也就是Adapter代码中注释掉的部分 ) , 后来根据这些改了之后并没有改变,而且别人是在 notifyItemRemoved() 报的异常,而我是在benas.remove()方法执行时报错的,后来才发现我传入的参数错误, 不应该传入onClick中的参数 int i 而是回调接口中 itemOnLongClickListener()方法中的参数 int position

      到这里RecyclerView的最基本的使用方法也就完了,当然更多的用法也都是在这些基础上进行扩展的,就留待日后发掘吧。

3、总结

  在这里给大家介绍两个比较实用的库:

  从上面也看出来了,RecyclerView灵活性是很高的,同时带来了一个问题就是很多东西需要我们自己去实现,比如Item的动画效果以及Item之间的分割线, 接下来的两个库自己尝试了一下配置和使用都是十分的方便,分别用在我们上面讲到的recyclerView.setItemAnimator()和recyclerView.addItemDecoration()处即可。

  RecyclerView动画库 :  https://github.com/wasabeef/recyclerview-animators .

  RecyclerView分割线库: https://github.com/yqritc/RecyclerView-FlexibleDivider .

猜你喜欢

转载自www.cnblogs.com/HelloHai/p/9272661.html