转载请注明:
http://blog.csdn.net/sinat_30276961/article/details/50365513
上一篇介绍了RecyclerView自定义分隔图的代码绘制方式,本篇将在上篇的基础上讲解RecyclerView的header和footer的添加和设定,并且讲完header和footer,RecyclerView的基础内容就讲完了。
ok,废话少说。我们都知道,在ListView里添加header和footer是一件再简单不过的事情,秒秒钟搞定。那么在RecyclerView里添加呢?
在前面几篇里,我已经讲过了,RecyclerView的大部分功能都分离出来了,需要我们自己去复写,然后添加进去。虽然增加了麻烦度,但是带来的是灵活和无限的创造性。所以,header和footer的添加也是需要我们自己去代码设定加进去的。
我们再回忆一下RecyclerView创建需要的几个核心:
LayoutManager(必须)
ItemDecoration (非必须)
Adapter(必须)
ItemAnimator (非必须)
那么,header和footer该怎么加进去呢?
我们先来回忆一下RecyclerView.Adapter里包含的接口:
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
public abstract void onBindViewHolder(VH holder, int position);
public int getItemViewType(int position) {
return 0;
}
public void setHasStableIds(boolean hasStableIds) {
if (hasObservers()) {
throw new IllegalStateException("Cannot change whether this adapter has " +
"stable IDs while the adapter has registered observers.");
}
mHasStableIds = hasStableIds;
}
public long getItemId(int position) {
return NO_ID;
}
public abstract int getItemCount();
public void onViewRecycled(VH holder) {
}
public boolean onFailedToRecycleView(VH holder) {
return false;
}
public void onViewAttachedToWindow(VH holder) {
}
public void onViewDetachedFromWindow(VH holder) {
}
public void registerAdapterDataObserver(AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
}
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
}
我把final的接口都摒弃掉了,上述接口是可以去复写的。从这些接口看,我们可以发现,一般情况,我们需要复写的接口不多,大致是如下几个:
onCreateViewHolder
onBindViewHolder
getItemCount
getItemId
当然,如果你需要实现复杂的功能,可能还需要如下接口:
getItemViewType(定义当前item的类型)
onViewRecycled(当前item被回收时调用,可用来释放绑定在view上的大数据,比方说Bitmap)
……(太多。。)
常用的接口,在前面几篇里已经都讲解过,这里重点讲下getItemViewType。
为啥要说这个接口呢?其实要实现在RecyclerView里添加headerView和footerView,这个接口是必不可少的。
getItemViewType是用来自己设定不同item的类型。既然如此,我们可以把header和footer看成是不同于一般item的类型不就行了。然后根据不同的viewType,我创建不同的view,也即是说,还需要修改
onCreateViewHolder(创建不同view)
onBindViewHolder(根据不同view,绑定不同数据)
getItemCount(header和footer不应该在此数量里)
getItemId(header占了index=0这个位置,所以需要调整)
ok,基本思路有了,现在想下方案。根据上述理念,我们目前能很容易想到的有两套方案:
1.在原先自己写的adapter里根据需要添加上header和footer。
2.通过装饰模式,在新的adapter里添加header和footer。
第一个方案,可行。
But!
要修改原来的代码,而且新改出来的adapter复用性差。
第二个方案,可行。
And!
不需要改动原来的adapter,复用性大大的提高。
鉴于此,我选择第二个方案(其实,你去看ListView的代码,你会发现,它添加header和footer的方式也是通过装饰模式的)。先来看看,我实现的添加headerView和footerView之后的效果:
这里添加的header和footer很简单,就是一个TextView。
ok,接下去,就是代码部分。我先贴出Adapter的代码:
public class HeaderRecyclerViewAdapter extends RecyclerView.Adapter{
public static final int ITEM_VIEW_TYPE_HEADER = -2;
public static final int ITEM_VIEW_TYPE_FOOTER = -3;
public static final int ITEM_VIEW_TYPE_ITEM = 0;
private RecyclerView.Adapter mAdapter;
private View mHeaderView;
private View mFooterView;
public HeaderRecyclerViewAdapter(View headerView, View footerView, RecyclerView.Adapter adapter) {
mHeaderView = headerView;
mFooterView = footerView;
mAdapter = adapter;
}
public RecyclerView.Adapter getWrappedAdapter() {
return mAdapter;
}
public boolean hasHeaderView() {
return mHeaderView != null;
}
public boolean hasFooterView() {
return mFooterView != null;
}
public int headerViewHeight() {
int height = 0;
if (mHeaderView != null) {
height = mHeaderView.getLayoutParams().height;
}
return height;
}
public int footerViewHeight() {
int height = 0;
if (mFooterView != null) {
height = mFooterView.getLayoutParams().height;
}
return height;
}
@Override
public int getItemViewType(int position) {
if (mHeaderView != null) {
if (position == 0) {
return ITEM_VIEW_TYPE_HEADER;
} else {
final int adjPosition = position - 1;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
return ITEM_VIEW_TYPE_ITEM;
}
}
}
} else {
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (position < adapterCount) {
return ITEM_VIEW_TYPE_ITEM;
}
}
}
return ITEM_VIEW_TYPE_FOOTER;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_VIEW_TYPE_HEADER) {
return new HeaderViewHolder(mHeaderView);
} else if (viewType == ITEM_VIEW_TYPE_FOOTER) {
return new HeaderViewHolder(mFooterView);
} else {
return mAdapter.onCreateViewHolder(parent, viewType);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final int viewType = getItemViewType(position);
if (viewType == ITEM_VIEW_TYPE_HEADER || viewType == ITEM_VIEW_TYPE_FOOTER) {
return;
} else {
int adjPosition = position;
if (mHeaderView != null) {
adjPosition--;
}
mAdapter.onBindViewHolder(holder, adjPosition);
}
}
@Override
public int getItemCount() {
if (mAdapter != null) {
return (mHeaderView == null ? 0 : 1)
+ (mFooterView == null ? 0 : 1)
+ mAdapter.getItemCount();
} else {
return (mHeaderView == null ? 0 : 1)
+ (mFooterView == null ? 0 : 1);
}
}
@Override
public long getItemId(int position) {
final boolean hasHeader = (mHeaderView != null);
final boolean hasFooter = (mFooterView != null);
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
}
if (hasHeader) {
if (position < adapterCount + 1) {
return position - 1;
} else {
return ITEM_VIEW_TYPE_FOOTER;
}
} else {
if (position < adapterCount) {
return position;
} else {
return ITEM_VIEW_TYPE_FOOTER;
}
}
}
static class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
这部分代码其实不复杂,只要思路理清了,实现起来不麻烦。
第2、3、4行,定义了几种viewType。可以看到header我是从-2开始的。这是因为-1是无效的item(INVALID_TYPE = -1)。当然,你也可以从1开始定义。
第6行的mAdapter就是需要包装的原始adapter。
第8、9行,我定义了一个headerView和footerView。在ListView里,可以添加多个headerView和footerView,这里,我就只实现添加一个header和footer。如果要和ListView一样,那就把View改为List< View >。
第46-71行,复写了getItemViewType。在原始的position==0的位置,用来放置header;最后一个位置,用来放置footer。
第74-82行,复写了onCreateViewHolder。根据不同的viewType,我创建不同的view和viewholder。
第85-96行,复写了onBindViewHolder。如果viewType是header或者footer,就直接return。如果是一般的item,还需要调整下它的position。如果有header,原先的position还要-1。这样一来,在被装饰的原始adapter里,得到的position就已经排除了header的占位。
后面的代码和上述差不多,就是把header和footer的情况特殊处理,这里就不讲了。
接着,我贴下RecyclerView复写的代码:
public class HeaderRecyclerView extends RecyclerView{
private View mHeaderView;
private View mFooterView;
public HeaderRecyclerView(Context context) {
super(context);
}
public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public HeaderRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addHeaderView(View headerView) {
mHeaderView = headerView;
}
public void addFooterView(View footerView) {
mFooterView = footerView;
}
public void setAdapter(Adapter adapter) {
if (mHeaderView == null && mFooterView == null) {
super.setAdapter(adapter);
} else {
adapter = new HeaderRecyclerViewAdapter(mHeaderView, mFooterView, adapter);
super.setAdapter(adapter);
}
}
public void removeHeaderView() {
mHeaderView = null;
}
public void removeFooterView() {
mFooterView = null;
}
}
上述代码就复写了setAdapter,代码很简单,不讲了。
接着是额外的部分,我把分隔图也重新改了一下,为了适应多了个header和footer。
先是HeaderLinearLayoutItemDecoration:
public class HeaderLinearLayoutItemDecoration extends RecyclerView.ItemDecoration{
final Context mContext;
final int mOrientation;
final Drawable mDividerDrawable;
int mDividerHeight;
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider,
android.R.attr.dividerHeight
};
public HeaderLinearLayoutItemDecoration(Context context, int orientation) {
mContext = context;
mOrientation = orientation;
TypedArray ta = context.obtainStyledAttributes(ATTRS);
mDividerDrawable = ta.getDrawable(0);
mDividerHeight = ta.getDimensionPixelSize(1, 1);
ta.recycle();
}
public HeaderLinearLayoutItemDecoration(Context context, int orientation, int dividerHeight) {
mOrientation = orientation;
mContext = context;
mDividerHeight = dividerHeight;
TypedArray ta = context.obtainStyledAttributes(ATTRS);
mDividerDrawable = ta.getDrawable(0);
ta.recycle();
}
public HeaderLinearLayoutItemDecoration(Context context, int orientation, Drawable dividerDrawable, int dividerHeight) {
mContext = context;
mOrientation = orientation;
mDividerDrawable = dividerDrawable;
mDividerHeight = dividerHeight;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawHorizontal(c, parent);
} else {
drawVertical(c, parent);
}
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight()-parent.getPaddingBottom();
final int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
final View child = parent.getChildAt(i);
final int position = parent.getChildAdapterPosition(child);
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight()+params.rightMargin;
final int right = left+mDividerHeight;
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth()-parent.getPaddingRight();
final int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
final View child = parent.getChildAt(i);
final int position = parent.getChildAdapterPosition(child);
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom()+params.bottomMargin;
final int bottom = top + mDividerHeight;
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
final int position = parent.getChildAdapterPosition(view);
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
return;
}
if (mOrientation == LinearLayoutManager.VERTICAL) {
outRect.bottom = mDividerHeight;
} else {
outRect.right = mDividerHeight;
}
}
}
代码其实和原先的LinearLayoutItemDecoration几乎一样,唯一的区别在于:我在drawHorizontal、drawVertical和getItemOffsets里在遍历child时,多加了个判断,如果是header或者footer,就不画不偏移。
再贴出HeaderGridLayoutItemDecoration:
public class HeaderGridLayoutItemDecoration extends RecyclerView.ItemDecoration{
final Context mContext;
final Drawable mDividerDrawable;
int mDividerHeight;
private static final int[] ATTRS = new int[] {
android.R.attr.listDivider,
android.R.attr.dividerHeight
};
public HeaderGridLayoutItemDecoration(Context context) {
mContext = context;
// 从主题去获取属性键值
TypedArray ta = context.obtainStyledAttributes(ATTRS);
mDividerDrawable = ta.getDrawable(0);
mDividerHeight = ta.getDimensionPixelSize(1, 1);
ta.recycle();
}
public HeaderGridLayoutItemDecoration(Context context, int height) {
mContext = context;
// 从主题去获取属性键值
TypedArray ta = context.obtainStyledAttributes(ATTRS);
mDividerDrawable = ta.getDrawable(0);
mDividerHeight = height;
ta.recycle();
}
public HeaderGridLayoutItemDecoration(Context context, Drawable drawable) {
mContext = context;
mDividerDrawable = drawable;
TypedArray ta = context.obtainStyledAttributes(ATTRS);
mDividerHeight = ta.getDimensionPixelSize(1, 1);
ta.recycle();
}
public HeaderGridLayoutItemDecoration(Context context, Drawable drawable, int height) {
mContext = context;
mDividerDrawable = drawable;
mDividerHeight = height;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
final int spanCount = manager.getSpanCount();
drawHorizontal(c, parent, state, spanCount);
drawVertical(c, parent, state, spanCount);
}
private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {
final int count = parent.getChildCount();
// 确定有几行
final int rowCount = count/spanCount + (count%spanCount==0?0:1);
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
for (int i = 0; i < rowCount; i++) {
final View child = parent.getChildAt(i*spanCount);
final int position = parent.getChildAdapterPosition(child);
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDividerHeight;
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state, final int spanCount) {
final int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
final View child = parent.getChildAt(i);
final int position = parent.getChildAdapterPosition(child);
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDividerHeight;
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin + mDividerHeight;
mDividerDrawable.setBounds(left, top, right, bottom);
mDividerDrawable.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final GridLayoutManager manager = (GridLayoutManager) parent.getLayoutManager();
final int spanCount = manager.getSpanCount();
final int position = parent.getChildAdapterPosition(view);
final int adjPosition = (int) parent.getAdapter().getItemId(position);
final int count = parent.getAdapter().getItemCount();
final int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
return;
}
if ((adjPosition == count -1) && (adjPosition % spanCount) == (spanCount - 1)) {
// 最后一个,如果也是最右边,那么就不需要偏移
} else if (adjPosition >= (count - (count % spanCount))) {
// 最下面一行,只要右边偏移就行
outRect.right = mDividerHeight;
} else if ((adjPosition % spanCount) == (spanCount - 1)) {
// 最右边一列,只要下面偏移就行
outRect.bottom = mDividerHeight;
} else {
// 其他的话,右边和下面都要偏移
outRect.set(0, 0, mDividerHeight, mDividerHeight);
}
}
}
这里,思路和HeaderLinearLayoutItemDecoration一样,就是在画和设置偏移的地方多加个header和footer的判断。
唯一不同的是,drawVertical和GridLayoutItemDecoration里的drawVertical不一样了。因为原先的实现方式是遍历span数量,并画spanCount数量的垂直drawable,并且是从屏幕最上方到屏幕最下方(parent.getPaddingTop和parent.getHeight() - parent.getPaddingBottom())。但是如果添加了header和footer,原先的方案就会使垂直drawable覆盖在header和footer上。并且如果是通过设置header和footer高度的偏移值来去掉header和footer那里的垂直drawable,也不好判断当前滑动位置是否包含header和footer,包含多少。所以,最好的方案是一个个item遍历画。
ok,到目前为止,所有需要的角色都已经讲完了。接着就是测试代码了:
public class AddHeaderViewTest extends ActionBarActivity {
HeaderRecyclerView mHeaderRecyclerView;
RecyclerViewAdapter mLinearLayoutAdapter;
HeaderLinearLayoutItemDecoration mLinearLayoutItemDecoration;
LinearLayoutManager mLinearLayoutManager;
GridRecyclerViewAdapter mGridLayoutAdapter;
HeaderGridLayoutItemDecoration mGridLayoutItemDecoration;
GridLayoutManager mGridLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_header_view_test);
mHeaderRecyclerView = (HeaderRecyclerView) findViewById(R.id.headerRecyclerView);
mLinearLayoutManager = new LinearLayoutManager(this);
mGridLayoutManager = new GridLayoutManager(this, 4);
// grid类型,需要复写这个方法
// 确定每个item的横跨span数
mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
return mGridLayoutManager.getSpanCount();
} else {
return 1;
}
}
});
mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);
mLinearLayoutItemDecoration = new HeaderLinearLayoutItemDecoration(this, LinearLayoutManager.VERTICAL, 4);
mGridLayoutItemDecoration = new HeaderGridLayoutItemDecoration(this, 18);
mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);
// 添加header
TextView headerView = new TextView(this);
headerView.setText("Header");
headerView.setTextColor(Color.GRAY);
headerView.setTextSize(18);
headerView.setGravity(Gravity.CENTER);
ViewGroup.LayoutParams headerParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
DensityUtil.dpToPx(60, getResources())
);
headerView.setLayoutParams(headerParams);
mHeaderRecyclerView.addHeaderView(headerView);
// 添加footer
TextView footerView = new TextView(this);
footerView.setText("Footer");
footerView.setTextColor(Color.GRAY);
footerView.setTextSize(18);
footerView.setGravity(Gravity.CENTER);
ViewGroup.LayoutParams footerParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
DensityUtil.dpToPx(60, getResources())
);
footerView.setLayoutParams(footerParams);
mHeaderRecyclerView.addFooterView(footerView);
mLinearLayoutAdapter = new RecyclerViewAdapter(this, R.layout.item_normal_recycler_view, 50);
mGridLayoutAdapter = new GridRecyclerViewAdapter(this, R.layout.item_recycler_view_grid, 100);
mLinearLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();
}
});
mGridLayoutAdapter.setOnItemClickListener(new CommonAdapter.OnRecyclerViewItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(AddHeaderViewTest.this, "The " + position + " click", Toast.LENGTH_SHORT).show();
}
});
mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_add_header_view_test, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_switch) {
if (mHeaderRecyclerView.getLayoutManager() == mLinearLayoutManager) {
mHeaderRecyclerView.setLayoutManager(mGridLayoutManager);
mHeaderRecyclerView.removeItemDecoration(mLinearLayoutItemDecoration);
mHeaderRecyclerView.addItemDecoration(mGridLayoutItemDecoration);
mHeaderRecyclerView.setAdapter(mGridLayoutAdapter);
} else {
mHeaderRecyclerView.setLayoutManager(mLinearLayoutManager);
mHeaderRecyclerView.removeItemDecoration(mGridLayoutItemDecoration);
mHeaderRecyclerView.addItemDecoration(mLinearLayoutItemDecoration);
mHeaderRecyclerView.setAdapter(mLinearLayoutAdapter);
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
这部分代码和原先的差不多,唯一不同点在于布局文件里的RecyclerView要使用自定义的HeaderRecyclerView。
还有一个地方是:
// grid类型,需要复写这个方法
// 确定每个item的横跨span数
mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
final int viewType = mHeaderRecyclerView.getAdapter().getItemViewType(position);
if (viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_HEADER
|| viewType == HeaderRecyclerViewAdapter.ITEM_VIEW_TYPE_FOOTER) {
return mGridLayoutManager.getSpanCount();
} else {
return 1;
}
}
});
对于GridLayoutManager,你需要通过setSpanSizeLookup复写getSpanSize这个接口。这个是用来确定每个item占据的span数量。默认情况下,返回的是1,也就是每个item占据1个span。
对于header和footer这两个item,每个都需要占据spanCount数量的span。
好了,关于RecyclerView添加headerView和footerView部分讲解完了。并且,RecyclerView的基础部分都讲解完了。
Have a good night!