androidandroid技术杂荟Android知识

Android中recycleview的adapter封装及实现

2017-04-29  本文已影响735人  昵称真难选

原文出自王艳涛的专栏转载请注明出处!

概述

在上一篇Android中recycleview的adapter封装中,实现了adapter的封装,大量减少了Adapter使用时的重复代码,同时拥有控制Item控件的能力,本文在上篇封装的基础上,对adapter的功能进行扩展,实现recycleview动态加载多布局的功能。
既然是功能扩展就要达到下面两个要求:

  1. 不需要加载多布局时,上篇封装的BaseAdapter可以和原来一样直接被继承,正常使用,用法不变;
  2. 当需要加载多布局时,不应该直接继承BaseAdapter,而因该指定一个继承自BaseAdapter的MultiLayoutsBaseAdapter类,让需要加载多布局的子类adapter继承。
  3. 指定一个Item布局资源Id数组,继承MultiLayoutsBaseAdapter的子类Adapter可以根据情况指定使用不同的Item布局。

BaseAdapter的代码优化

结合上一篇Android中recycleview的adapter封装封装后的BaseAdapter代码,分析其需要改进的地方,如下放代码中的注释。

待改进的BaseAdapter代码分析

public abstract class BaseAdp<T> extends RecyclerView.Adapter<BaseHolder> {
  Context context;
  List<T> data;
  int layoutId;//改进1:属性可以移除
  //改进2:需要增加一个布局资源Id数组layoutIds

  public BaseAdp(Context context, List<T> data, int layoutId) {
    this.context = context;
    this.data = data;
    this.layoutId = layoutId;//改进3:移除
    //改进4:将layoutId放到布局资源Id数组layoutIds中
  }

  //改进5:需要增加一个能够接收传入的布局资源Id数组layoutIds的构造函数

  public void setData(List<T> data) {
    this.data = data;
  }

  public List<T> getData() {
    return this.data;
  }

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

  @Override
  public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //改进6:根据viewType,从局资源Id数组layoutIds中指定layoutId
    return BaseHolder.getHolder(context, parent, layoutId);
  }

  @Override
  public void onBindViewHolder(BaseHolder holder, int position) {
    onBind(holder, data.get(position), position);
  }
  public abstract void onBind(BaseHolder holder, T t, int position);
}

改进后的BaseAdapter代码分析

public abstract class BaseAdapter<T> extends RecyclerView.Adapter<BaseHolder> {
    Context context;
    List<T> data;
    int []layoutIds;//布局资源Id数组layoutIds中

    public BaseAdapter(Context context, List<T> data, int layoutId) {
        this.context = context;
        this.data = data;
        //不使用多布局时的构造函数,将layoutId放到布局资源Id数组layoutIds中
        this.layoutIds = new int[]{layoutId};
    }
    //使用多布局时的构造函数,可以接收传入的布局资源Id数组
    public BaseAdapter(Context context, List<T> data, int[] layoutIds) {
        this.context = context;
        this.data = data;
        this.layoutIds = layoutIds;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public List<T> getData() {
        return this.data;
    }

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

    @Override
    public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      //根据viewType从布局资源数组中加载指定的布局
      //1.当不需要加载多布局时,子类继承BaseAdapter,不用覆写getItemViewType()
      //此时,viewType值默认为0;
      //2.当需要加载多布局时,子类继承MultiLayoutsBaseAdapter,需要覆写getItemViewType()
      //此时,viewType值为子类adapter指定的值;
        return BaseHolder.getHolder(context, parent, layoutIds[viewType]);
    }

    @Override
    public void onBindViewHolder(BaseHolder holder, int position) {
        onBind(holder, data.get(position), position);
    }

    public abstract void onBind(BaseHolder holder, T t, int position);
}

多布局动态加载的MultiLayoutsBaseAdapter基类

多布局动态加载的MultiLayoutsBaseAdapter基类中,应该将两种操作下放的子类adapter中:

  1. 指定特定布局类型的操作;
  2. 对加载后的特定布局中的控件操作。

具体MultiLayoutsBaseAdapter基类代码如下

public abstract class MultiLayoutsBaseAdapter<T> extends BaseAdapter<T> {

    public MultiLayoutsBaseAdapter(Context context, List<T> data, int[] layoutIds) {
        super(context, data, layoutIds);
    }

    @Override
    public int getItemViewType(int position) {
      //调用子类继承实现的获取指定布局类型的抽象方法
        return getItemType(position);
    }

    @Override
    public void onBind(BaseHolder holder, T t, int position) {
      //调用子类继承实现的对加载后特定布局中控件操作的抽象方法,同时传入布局类型
        onBinds(holder, t, position, getItemViewType(position));
    }
    //获取指定的布局类型的抽象方法,让子类继承实现
    public abstract int getItemType(int position);
    //对加载后的特定布局中的控件操作的抽象方法,让子类继承实现
    public abstract void onBinds(BaseHolder holder, T t, int position, int itemType);
}

使用方法

单一布局时使用方法

此时,使用方法同上一篇Android中recycleview的adapter封装后的使用一样;

加载多布局时使用方法

子类继承MultiLayoutsBaseAdapter,实现抽象函数。

public class Contacts2Adapter extends MultiLayoutsBaseAdapter<Contact>{
    public Contacts2Adapter(Context context, List<Contact> data, int []layoutIds) {
        super(context, data, layoutIds);
    }

    @Override
    public int getItemType(int position) {
        int itemType = 0;
        //自定义操作为itemType赋值
        return itemType;
    }

    @Override
    public void onBinds(BaseHolder holder, Contact contact, int position, int itemType) {
        //根据itemType,为不同的Item布局指定不同的操作
        switch (itemType){
            case 0:
                //自定义操作
                //根据控件Id获取Item内部的控件
                TextView tvName = holder.getView(R.id.tvName);
                tvName.setText(contact.getName());
                //根据Item中的控件Id向控件添加事件监听
                holder.setOnClickListener(R.id.ivPhone, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //自定义的代码
                    }
                });
                break;
            //……
        }
    }
}

子类初始化时传入Item布局资源数组

int []layoutIds = new int[]{R.layout.item_0, R.layout.item_1, R.layout.item_2};
Contacts2Adapter contacts2Adapter =
  new Contacts2Adapter(getHoldingActivity(), contacts, layoutIds);
上一篇下一篇

猜你喜欢

热点阅读