以前写过一篇关于RecyclerView的头部尾部的添加
也有一个Demo 不过Linear Grid Stagge三个是分开的 如下图1 今天的是一个整合的DRecyclerView 如下图二 讲一下实现过程
这是整合的 使用更加方便
先看效果图
- 首先来分析最简单的 也就是LinearLayoutManager情况下的 添加头部 尾部 和中间插入
在继承RecyclerView的使用中 两个关键方法
onCreateViewHolder 和 onBindViewHolder
onCreateViewHolder 创建布局View
onBindViewHolder 绑定数据
所以我们要在显示不同的布局上做处理 就只能在 onCreateViewHolder 创建的时候做处理
观察 onCreateViewHolder 这个方法 通过该方法参数
onCreateViewHolder(ViewGroup parent, int viewType) {---}
发现 我们能做处理的 只有viewType 这个字段 看字面意思也能猜到是不同view的类型
然后我们看源码
然后 getItemType(int position) 这个方法上面说了 用来返回不同的View的type 也就是说 onCreateViewHolder中的ViewType来自这个方法 默认是返回0 我们在自己的处理中重写这个方法就行了
我们就返回 当前进来的position
然后在onCreateViewHolder中自己处理
好 现在在分析 整个类 要具备的一些条件
一个HeadViews 的集合 缓存所有的HeadView
一个FootViews的集合 缓存所有的FootView
一个中间插入的View的 集合 缓存所有的插入View[这个View就是数据列表中不同的类型做不同的布局 一般滑动很多显示一个 推荐 等等]
整个DRecyclerViewAdapater 代码如下
public class DRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final String Tag = DRecyclerViewAdapter.class.getName();
private RecyclerView.Adapter mInnerAdapter;
public DRecyclerViewAdapter(DBaseRecyclerViewAdapter adapter) {
setAdapter(adapter);
}
public void setAdapter(DBaseRecyclerViewAdapter myAdapter) {
if (myAdapter != null) {
if (!(myAdapter instanceof RecyclerView.Adapter))
throw new RuntimeException("your adapter must be a RecyclerView.Adapter");
}
this.mInnerAdapter = myAdapter;
myAdapter.setDRecyclerViewAdapter(this);
}
/**
* head foot list cache
*/
private List<View> mHeadViews = new ArrayList<View>();
private List<View> mFootViews = new ArrayList<View>();
private List<View> mRandomViews = new ArrayList<View>();
private SparseArray<Integer> mRandomViews_position = new SparseArray<Integer>();
/**
* addHead to recyclerview
*
* @param view
*/
public void addHeadView(View view) {
mHeadViews.add(view);
}
/**
* addFoot to RecyclerView
*
* @param view
*/
public void addFootView(View view) {
mFootViews.add(view);
}
/**
* 使用一次 存下来 后续 好查找
*/
private int index=0;
public void addRandomView(View view, int posistion) {
mRandomViews_position.append(posistion,index);
index++;
mRandomViews.add(view);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
DRecyclerViewHolder dRecyclerViewHolder;
Log.e(Tag, "当前type " + viewType);
if (viewType < mHeadViews.size()) {
Log.e(Tag, "headView" + viewType);
return new DRecyclerViewHolder(mHeadViews.get(viewType));
} else if (viewType >= mHeadViews.size() && viewType < mHeadViews.size() + mInnerAdapter.getItemCount()) {
if (mRandomViews_position.get(viewType - mHeadViews.size())!=null) {
View view = mRandomViews.get(mRandomViews_position.get(viewType - mHeadViews.size()));
return new DRecyclerViewHolder(view);
}
return mInnerAdapter.onCreateViewHolder(parent, viewType - mHeadViews.size());
} else {
Log.e(Tag, "FootView" + viewType);
int position = viewType - mHeadViews.size() - mInnerAdapter.getItemCount();
if (position >= 0 && position < mFootViews.size()) {
return new DRecyclerViewHolder(mFootViews.get(position));
} else {
return null;
}
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position >= mHeadViews.size() && position < mHeadViews.size() + mInnerAdapter.getItemCount()) {
//不包括那些插入的
if (mRandomViews_position.get(position - mHeadViews.size())==null)
mInnerAdapter.onBindViewHolder(holder, position - mHeadViews.size());
} else {
/**
* 瀑布流的设置处理
*/
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
((StaggeredGridLayoutManager.LayoutParams) layoutParams).setFullSpan(true);
}
}
}
@Override
public int getItemCount() {
return mHeadViews.size() + mInnerAdapter.getItemCount() + mFootViews.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
public int getFootSize() {
return mFootViews.size();
}
public int getHeadSize() {
return mHeadViews.size();
}
public boolean isHeader(int position) {
return position < mHeadViews.size() ? true : false;
}
public boolean isFooter(int position) {
return position >= mHeadViews.size() + mInnerAdapter.getItemCount() ? true : false;
}
public boolean isRandom(int position){
Log.e("isRandom",position+" "+mRandomViews_position.get(position-mHeadViews.size()));
return mRandomViews_position.get(position-mHeadViews.size())!=null?true:false;
}
static class DRecyclerViewHolder extends RecyclerView.ViewHolder {
public DRecyclerViewHolder(View itemView) {
super(itemView);
}
}
}
可以看到 逻辑处理在onCreateViewHolder中
根据进来的ViewType 也就是position
整套罗不难 就是根据position的位置来区分来区分属于哪个地方的View
mRandomViews_position 这个是处理中间数据不同的记录 用的SparseArray 类似Map 效率高些 节约内存 查找内部二分查找 不多介绍
目的是 记录 列表数据中的 那些位置是插入的 不同的View
上面是LinearLayoutManager的情况 属于最简单的情况
分析一下GridLayoutManager 这个 主要方法就是 这个方法 源码里面有
设置每个Item 所占得位置 默认是1 如果你的2列 这里可以在添加头部的时候 设置为2 就会占一整行了
所以 封装一个 类 继承GridLayoutManager.SpanSizeLookup 是头部 尾部 插入位置 都占用一个大格
/**
* Created by Daemon on 2015/11/10.
*/
public class DSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
private DRecyclerViewAdapter adapter;
private int mSpanSize = 1;
public DSpanSizeLookup(DRecyclerViewAdapter adapter, int spanSize) {
this.adapter = adapter;
this.mSpanSize = spanSize;
}
@Override
public int getSpanSize(int position) {
boolean isHeaderOrFooterOrRandom = adapter.isHeader(position) || adapter.isFooter(position)
|| adapter.isRandom(position);
return isHeaderOrFooterOrRandom ? mSpanSize : 1;
}
}
所以在使用的时候 设置这个就行了 其余的不变
在看看 StaggeredGridLayoutManager 这里就要用到
LayoutParams lp = (LayoutParams)
view.getLayoutParams();lp.setFullSpan(true);
这种方法 来设置 不同的占用列数 重写onMeasure方法 处理
这样就是整个的使用原理
至于其中的DBaseRecyclerViewAdapter DBaseRecyclerViewHolder 等等都是一些辅助类 更加方便使用 和添加头部 尾部 没得啥具体关系 不介绍了
MainActivity的使用代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private DRecyclerViewAdapter dRecyclerViewAdapter;
private LinearLayoutManager linearLayoutManager;
private Button bt_linear;
private Button bt_grid;
private Button bt_stagge;
private MyAdpater myAdpater;
private GridLayoutManager gridLayoutManager;
private DStaggeredGridLayoutManager staggeLayoutManager;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_linear:
if (linearLayoutManager == null) {
linearLayoutManager = new LinearLayoutManager(MainActivity.this);
}
rcv_list.setLayoutManager(linearLayoutManager);
dRecyclerViewAdapter.notifyDataSetChanged();
rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
@Override
public void onLoadNextPage(RecyclerView view) {
Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
}
});
break;
case R.id.bt_grid:
if (gridLayoutManager == null) {
gridLayoutManager = new GridLayoutManager(MainActivity.this, 2);
gridLayoutManager.setSpanSizeLookup(new DSpanSizeLookup(dRecyclerViewAdapter, gridLayoutManager.getSpanCount()));
}
rcv_list.setLayoutManager(gridLayoutManager);
dRecyclerViewAdapter.notifyDataSetChanged();
rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
@Override
public void onLoadNextPage(RecyclerView view) {
Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
}
});
break;
case R.id.bt_stagge:
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
break;
}
}
private RecyclerView rcv_list;
private List<Data> list;
public static class Data{
public String value;
public int type;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rcv_list = (RecyclerView) findViewById(R.id.rcv_list);
bt_linear = (Button) findViewById(R.id.bt_linear);
bt_grid = (Button) findViewById(R.id.bt_grid);
bt_stagge = (Button) findViewById(R.id.bt_stagge);
list = new ArrayList<Data>();
bt_linear.setOnClickListener(this);
bt_grid.setOnClickListener(this);
bt_stagge.setOnClickListener(this);
for (int i = 0; i < 20; i++) {
Data data=new Data();
data.value="Daemon data " + i;
data.type=0;
list.add(data);
//一种判断标示 可以根据实际需求来做标识
if (i % 5 == 0) {
data.type=1;
}
}
myAdpater = new MyAdpater(list, this);
dRecyclerViewAdapter = new DRecyclerViewAdapter(myAdpater);
linearLayoutManager = new LinearLayoutManager(MainActivity.this);
rcv_list.setLayoutManager(linearLayoutManager);
addHeadViews();
addFootviews();
addRandomView();
myAdpater.setOnClickItemListsner(new DBaseRecyclerViewAdapter.OnClickItemListsner() {
@Override
public void onClick(int poisiton) {
Toast.makeText(MainActivity.this, poisiton + "", Toast.LENGTH_SHORT).show();
}
});
rcv_list.setAdapter(dRecyclerViewAdapter);
rcv_list.addOnScrollListener(new DRecyclerViewScrollListener() {
@Override
public void onLoadNextPage(RecyclerView view) {
Toast.makeText(MainActivity.this,"底部",Toast.LENGTH_SHORT).show();
}
});
}
/**
* 添加全部的Views 中间插入的广告栏 等等
*/
private void addRandomView() {
for(int i=0 ; i<list.size();i++){
if(list.get(i).type==1){
View view = LayoutInflater.from(this).inflate(R.layout.random_item, rcv_list, false);
dRecyclerViewAdapter.addRandomView(view,i);
}
}
}
/**
* add HeadView
*/
private void addHeadViews() {
View head = LayoutInflater.from(this).inflate(R.layout.head, rcv_list, false);
View head1 = LayoutInflater.from(this).inflate(R.layout.head, rcv_list, false);
dRecyclerViewAdapter.addHeadView(head);
dRecyclerViewAdapter.addHeadView(head1);
}
/**
* add Footview
*/
private void addFootviews() {
View foot = LayoutInflater.from(this).inflate(R.layout.foot, rcv_list, false);
View foot1 = LayoutInflater.from(this).inflate(R.layout.foot, rcv_list, false);
dRecyclerViewAdapter.addFootView(foot);
dRecyclerViewAdapter.addFootView(foot1);
}
/**
* 继承封装过的DBaseRecyclerViewAdapter
*/
class MyAdpater extends DBaseRecyclerViewAdapter<Data> {
public MyAdpater(List<Data> mDatas, Context mContext) {
super(mDatas, mContext);
}
@Override
protected DBaseRecyclerViewHolder onCreateViewHolder1(ViewGroup parent, int viewType) {
return new MyViewHoder(parent, R.layout.item, this);
}
}
/**
* 继承封装过的 DBaseRecyclerViewHolder
*/
class MyViewHoder extends DBaseRecyclerViewHolder<Data> implements View.OnClickListener {
private TextView tv_content;
public MyViewHoder(ViewGroup parent, @LayoutRes int res, DBaseRecyclerViewAdapter dBaseRecyclerViewAdapter) {
super(parent, res, dBaseRecyclerViewAdapter);
tv_content = $(R.id.tv_content);
itemView.setOnClickListener(this);
}
@Override
public void setData(Data data, int position) {
//每次默认初始化 因为Stagge会改变高度
ViewGroup.LayoutParams layoutParams1 = tv_content.getLayoutParams();
layoutParams1.height = 80;
tv_content.setLayoutParams(layoutParams1);
tv_content.setText(data.value);
}
@Override
public void onClick(View v) {
if (getOnClickItemListsner() != null) {
getOnClickItemListsner().onClick(getAdapterItemPosition());
}
}
}
}
放在Github上面 整个Demo