RecyclerView通用泛型适配器

大家好,我们上一次讲了ListView的通用适配器写法,大家还记得吗?其实简单来说就是在在ViewHolder上面多花了功夫,然后添加了一个抽象方法用于接口回调,来让我们实现自定义添加控件。如果忘记了大家可以去看我上一篇的ListVIew介绍: ListView通用适配器

今天我们来看一下一个跟ListView很像的东西,叫做RecyclerView,要说他跟ListView有什么不一样的呢?这么说吧,ListView能做的事情,RecyclerView也能做,而且还能做一些ListView不能做的事情,比如横向线性布局滑动,或者瀑布流布局等,如果没用过RecyclerView的,大家可以看一下我写的RecycleerView使用:


我想先说一下我们设计通用适配器的设计原理:

我们的通用适配器和普通适配器不同:首先我们不知道我们要展现什么样的布局,其次,我们也不知道布局中的控件类型,更不知道控件的id,在这种三不知的情况下,唯一能让我们实现的,只有 通过回调方法,我们通过在适配器中添加抽象类或接口,把让控件和数据连接的过程通过回调方法实现。

而为了获取我们的控件,我们加大了ViewHolder的作用空间,让他不单单存储控件,直接用来存储布局,反正布局和控件是我们通过参数传入的,布局中控件的id我们自己知道,在回调方法中自行操作就好了。这就是通用适配器的原理。

在正式写代码之前,我们首先写一下我们的基础代码,包括控件布局和bean类:

private RecyclerView mRv;
    private List<Book> bookList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        beans();
        initViews();
    }

    private void beans() {
        bookList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            bookList.add(new Book("我是第" + (i + 1) + "本书", "10" + i, R.drawable.a, true));
        }
        for (int i = 5; i < 10; i++) {
            bookList.add(new Book("我是第" + (i + 1) + "本书", "10" + i, R.drawable.b, false));
        }
        for (int i = 10; i < 15; i++) {
            bookList.add(new Book("我是第" + (i + 1) + "本书", "10" + i, R.drawable.c, true));
        }
        for (int i = 15; i < 20; i++) {
            bookList.add(new Book("我是第" + (i + 1) + "本书", "10" + i, R.drawable.d, false));
        }
    }

    private void initViews() {
        mRv = (RecyclerView) findViewById(R.id.mrv);
    }

1.创建适配器:

1).我们要让适配器继承RecyclerView的Adapter,
public class RvAdapter extends RecyclerView.Adapter {
}
         2).我们需要创建一个类MyViewHolder去继承RecyclerView的ViewHolder,这个RecyclerView跟我们的ListView有一点不太一样,他有自己的ViewHolder类,所以我们需要去继承他。

public static class MyViewHolder extends RecyclerView.ViewHolder{

        public MyViewHolder(View itemView) {
            super(itemView);
        }
    }

由于等会儿要把ViewHolder写成单例模式,所以我这里就直接写成静态内部类啦。

3).添加泛型和指定泛型

添加泛型我们不用多解释,因为我们要做的是万能适配器,适配的数据类型不确定,所以要用泛型来表示。

 
  
public class RvAdapter<T> extends RecyclerView.Adapter<RvAdapter.MyViewHolder>

指定泛型是在我们RecyclerView.Adapter后面,指定成我们刚刚继承RecyclerView.Adapter的类名。

4).重写方法:

我们RecyclerView需要重写三个方法,onCreateViewHolder、onBindViewHolder和getItemCount

在这之前我们先把属性添加到adapter中。我们需要两个属性,一个是我们布局id,另一个是我们的数据集合。

    private int mLayRes;
    private List<T> list;

由于我们发现RecyclerView中没有convertView这个属性,所以我们要创建一个View 属性,用于优化。

    private View convertView;

最简单的就是getItemCount方法了,我们只需要返回list的大小就好。

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

然后是onCreateViewHolder。

在这之前我们先完善一下我们的MyViewHolder类吧。

完善MyViewHolder类:

首先我们把构造方法改为私有构造方法,我们发现他构造方法中有一个View参数,那我们在MyViewHolder中添加一个属性来接收他。

private View itemView;
private MyViewHolder(View itemView) {
    super(itemView);
    this.itemView = itemView;
}

然后我们要创建一个静态方法来bind,用来获取ViewHolder对象:

public static MyViewHolder bind(ViewGroup parent,int viewType,int LayRes,View convertView){
            MyViewHolder holder;
            if(convertView == null){
                convertView = LayoutInflater.from(parent.getContext()).inflate(LayRes,parent,false);
                holder = new MyViewHolder(convertView);
            }else
                holder = (MyViewHolder) convertView.getTag();

            return holder;
        }

里面的几个参数大家都可以看懂的,这段代码是不是跟ListView中getView的优化很像呢?

我们的MyViewHolder还需要一个必要的属性:

 
   
private SparseArray<View> views = new SparseArray<>();

我们用SparseArray来存储控件,指定泛型为View,他可以直接根据我们控件的id来查找对应id的控件。

现在我们的MyViewHolder还需要几个方法,用来辅助我们操作:

①.获取指定控件

public <T extends View> T getView(int id) {
            T t = (T) views.get(id);
            if (t == null) {
                t = itemView.findViewById(id);
                views.put(id, t);
            }
            return t;
        }

我们通过getView方法,通过id获取到对应控件。

②.添加文本数据

public MyViewHolder setText(int id, CharSequence text) {
            TextView view = getView(id);
            view.setText(text);
            return this;
        }

③.添加图片

public MyViewHolder setImgRes(int id, int resId) {
            ImageView view = getView(id);
            view.setImageResource(resId);
            return this;
        }
④.。。。。。其实到现在这个适配器的ViewHolder已经基本写好了,我们只添加了两个最基本的,文字和图片,如果想要拓展就可以自己添加方法了。好了。

现在我们在onCreateViewHolder中通过bind方法得到一个MyViewHolder对象。

 @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return MyViewHolder.bind(parent,viewType,mLayRes,convertView);
    }

然后我们的onBindViewHolder方法也很简单,由于我们不知道什么样的控件,什么样的布局,所以我们没有办法把onBindViewHolder写死,所以我们写一个抽象类用于回调。

public abstract void bindView(MyViewHolder holder,int position);

同时在onBindViewHolder中调用这个方法:

@Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        bindView(holder,position);
    }


好了,到现在为止我们的适配器就已经全部写完了,我们来检验一下看一下效果如何:

RvAdapter<Book> adapter = new RvAdapter<Book>(android.R.layout.activity_list_item, bookList) {
            @Override
            public void bindView(MyViewHolder holder, int position) {
                holder.setText(android.R.id.text1, bookList.get(position).getName());
                holder.setImgRes(android.R.id.icon, bookList.get(position).getPic());
            }
        };
        LinearLayoutManager manager = new LinearLayoutManager(this);
        mRv.setLayoutManager(manager);
        mRv.setAdapter(adapter);

为了方便,我直接使用系统内置的布局了哈哈哈哈,别说我懒。



看来是可以使用的,现在大家知道如何配置RecyclerView的通用适配器了吗?

猜你喜欢

转载自blog.csdn.net/zy_jibai/article/details/80276793