前言
Android RecyclerView的适配器。面对各种列表的需求,急需要梳理一下,抽象出一个快速开发列表的适配器,减小代码量,提高开发效率。
可展开的Adapter支持的功能如下:
- 支持两行可展开能力(单一类型适配)
- 支持空状态;
- 支持Header、Footer的适配
- LoadMore的适配
使用类:BaseExpandableRecyclerViewAdapter
demo地址:
1. 用法
(1)基本可展开的group写法
- a 新增 父SampleGroupBean和子SampleChildBean
- b 定义对应的父ViewHolder和子ViewHolder
- c 实现adapter中对应的onCreateGroupViewHolder和onCreateChildViewHolder、onBindGroupViewHolder和onBindChildViewHolder
public class SampleAdapter extends
BaseExpandableRecyclerViewAdapter<SampleGroupBean, SampleChildBean, SampleAdapter.GroupVH, SampleAdapter.ChildVH> {
private List<SampleGroupBean> mList;
public SampleAdapter(List<SampleGroupBean> list) {
mList = list;
}
@Override
public int getGroupCount() {
return mList.size();
}
@Override
public SampleGroupBean getGroupItem(int position) {
return mList.get(position);
}
@Override
public GroupVH onCreateGroupViewHolder(ViewGroup parent, int groupViewType) {
return new GroupVH(
LayoutInflater.from(parent.getContext())
.inflate(R.layout.listitem_group, parent, false));
}
@Override
public ChildVH onCreateChildViewHolder(ViewGroup parent, int childViewType) {
return new ChildVH(
LayoutInflater.from(parent.getContext())
.inflate(R.layout.listitem_child, parent, false));
}
@Override
public void onBindGroupViewHolder(GroupVH holder, SampleGroupBean sampleGroupBean, boolean isExpanding) {
holder.nameTv.setText(sampleGroupBean.getName());
if (sampleGroupBean.isExpandable()) {
holder.foldIv.setVisibility(View.VISIBLE);
holder.foldIv.setImageResource(isExpanding ? R.drawable.ic_arrow_expanding : R.drawable.ic_arrow_folding);
} else {
holder.foldIv.setVisibility(View.INVISIBLE);
}
}
@Override
public void onBindChildViewHolder(ChildVH holder, SampleGroupBean groupBean, SampleChildBean sampleChildBean) {
holder.nameTv.setText(sampleChildBean.getName());
}
static class GroupVH extends BaseExpandableRecyclerViewAdapter.BaseGroupViewHolder {
ImageView foldIv;
TextView nameTv;
GroupVH(View itemView) {
super(itemView);
foldIv = (ImageView) itemView.findViewById(R.id.group_item_indicator);
nameTv = (TextView) itemView.findViewById(R.id.group_item_name);
}
@Override
protected void onExpandStatusChanged(RecyclerView.Adapter relatedAdapter, boolean isExpanding) {
foldIv.setImageResource(isExpanding ? R.drawable.ic_arrow_expanding : R.drawable.ic_arrow_folding);
}
}
static class ChildVH extends RecyclerView.ViewHolder {
TextView nameTv;
ChildVH(View itemView) {
super(itemView);
nameTv = (TextView) itemView.findViewById(R.id.child_item_name);
}
}
}
(2)支持Header、Footer写法
adapter.setHeaderViewProducer(new ViewProducer() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new DefaultEmptyViewHolder(
LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false)
);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder) {
}
});
adapter.setFooterViewProducer(new ViewProducer() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new DefaultEmptyViewHolder(
LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_footview, parent, false)
);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder) {
}
});
(3)支持EmptyView写法
adapter.setEmptyViewProducer(new ViewProducer() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new DefaultEmptyViewHolder(
LayoutInflater.from(parent.getContext()).inflate(R.layout.empty, parent, false)
);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder) {
}
});
(4)支持LoadMore写法
adapter.setLoadMoreProducer(new ViewProducer() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new DefaultEmptyViewHolder(
LayoutInflater.from(parent.getContext()).inflate(R.layout.load_next_page, parent, false)
);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder) {
}
});
(5)点击的监听
adapter.setListener(new BaseExpandableRecyclerViewAdapter.ExpandableRecyclerViewOnClickListener<GroupBean,
SampleChildBean>() {
@Override
public boolean onGroupLongClicked(GroupBean groupItem) {
return false;
}
@Override
public boolean onInterceptGroupExpandEvent(GroupBean groupItem, boolean isExpand) {
return false;
}
@Override
public void onGroupClicked(GroupBean groupItem) {
}
@Override
public void onChildClicked(GroupBean groupItem, SampleChildBean childItem) {
}
});
2. 基本原理
基本继承RecyclerView.Adapter复写的类中封装了一些常用到的写法,抽象出来
(1)在getItemViewType中分别对ViewType做区分:VIEW_TYPE_EMPTY > VIEW_TYPE_LOADMORE > VIEW_TYPE_FOOT > VIEW_TYPE_HEAD。其中将Group和Child也当作为一种类型进行区分,根据position、及group和child的数量可以计算出折叠或者展开之后的位置。
(2)抽象出getGroupCount、getGroupItem、onCreateGroupViewHolder、onBindGroupViewHolder
(3)抽象出onCreateChildViewHolder、onBindChildViewHolder
(4)抽象出BaseGroupBean,包含getChildCount、getChildAt、isExpandable方法
(5)在onCreateViewHolder中根据type进行创建不同的布局 ,并进行封装
switch (viewType & TYPE_MASK) {
case TYPE_EMPTY:
return mEmptyViewProducer.onCreateViewHolder(parent);
case TYPE_HEADER:
return mHeaderViewProducer.onCreateViewHolder(parent);
case TYPE_FOOTER:
return mFooterViewProducer.onCreateViewHolder(parent);
case TYPE_LOAD_MORE:
return mLoadMoreViewProducer.onCreateViewHolder(parent);
case TYPE_CHILD:
return onCreateChildViewHolder(parent, viewType ^ TYPE_CHILD);
case TYPE_GROUP:
return onCreateGroupViewHolder(parent, viewType ^ TYPE_GROUP);
default:
throw new IllegalStateException(
String.format(Locale.getDefault(), "Illegal view type : viewType[%d]", viewType));
}
(6)在getItemCount中将几个类型的布局数量算进去
(7)在onBindViewHolder中进行实际数据绑定的封装。
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
switch (holder.getItemViewType() & TYPE_MASK) {
case TYPE_EMPTY:
mEmptyViewProducer.onBindViewHolder(holder);
break;
case TYPE_HEADER:
mHeaderViewProducer.onBindViewHolder(holder);
break;
case TYPE_FOOTER:
mFooterViewProducer.onBindViewHolder(holder);
break;
case TYPE_LOAD_MORE:
mLoadMoreViewProducer.onBindViewHolder(holder);
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMoreRequested();
}
break;
case TYPE_CHILD:
final int[] childCoord = translateToDoubleIndex(position);
GroupBean groupBean = getGroupItem(childCoord[0]);
bindChildViewHolder((ChildViewHolder) holder, groupBean, groupBean.getChildAt(childCoord[1]), payloads);
break;
case TYPE_GROUP:
bindGroupViewHolder((GroupViewHolder) holder, getGroupItem(translateToDoubleIndex(position)[0]), payloads);
break;
default:
throw new IllegalStateException(
String.format(Locale.getDefault(), "Illegal view type : position [%d] ,itemViewType[%d]", position, holder.getItemViewType()));
}
}
3. 持续迭代
- 多种类型适配
- 支持grid
- 支持stickyHead