![](https://img.haomeiwen.com/i2706458/43302c70736ef888.jpg)
原文出自王艳涛的专栏转载请注明出处!
概述
在上一篇Android中recycleview的adapter封装中,实现了adapter的封装,大量减少了Adapter使用时的重复代码,同时拥有控制Item控件的能力,本文在上篇封装的基础上,对adapter的功能进行扩展,实现recycleview动态加载多布局的功能。
既然是功能扩展就要达到下面两个要求:
- 不需要加载多布局时,上篇封装的BaseAdapter可以和原来一样直接被继承,正常使用,用法不变;
- 当需要加载多布局时,不应该直接继承BaseAdapter,而因该指定一个继承自BaseAdapter的MultiLayoutsBaseAdapter类,让需要加载多布局的子类adapter继承。
- 指定一个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中:
- 指定特定布局类型的操作;
- 对加载后的特定布局中的控件操作。
具体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);
网友评论