一、背景
在RecyclerView还没出来时,列表布局基本都是用 ListView,app 中一般都会有这种设计,上面一个 banner 轮播图,下面一个列表,特别是一些电商类,新闻类 app。
下面是最终效果:
向上滑动列表时,上面的轮播图就会被滑上去,显然是一体的,用 ListView 时,可以把上面的轮播图控件作为一个 HeaderView 加到 ListView 中,爽的是 ListView 的 API 中已经提供了 addHeaderView() 方法,直接使用就能实现上面的效果,不爽的是 RecyclerView 中居然没提供这个方法,体验了爽的之后再体验不爽的,那就不爽了,只能自己加咯。
二、实现方式
还是在 itemViewType 上做文章,接着上篇文章的 BaseAdapter 来修改,RecyclerView系列之加载更多
增加一个 HeaderType
...
@Override
public int getItemViewType(int position) {
if (isFooterView(position)) {
return TYPE_FOOTER_VIEW;
}
if (isHeaderView(position)) {
return TYPE_HEADER_VIEW;
}
return TYPE_CONTENT_VIEW;
}
@Override
public int getItemCount() {
if (null == mDatas) {
return 0;
}
return mDatas.size() + getFooterViewCount() + getHeaderViewCount();
}
private boolean isHeaderView(int position) {
return position < getHeaderViewCount();
}
protected int getHeaderViewCount() {
if (mHeaderLayout == null || mHeaderLayout.getChildCount() == 0) {
return 0;
}
return 1;
}
...
同时 getItemCount 也要增加 headerView 的个数,然后在 onCreateViewHolder 里通过 itemViewType 判断创建什么 ViewHolder
...
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
BaseViewHolder baseViewHolder = null;
switch (viewType) {
case TYPE_CONTENT_VIEW:
baseViewHolder = BaseViewHolder.create(getLayoutId(), parent);
break;
case TYPE_FOOTER_VIEW:
if (mFooterLayout == null) {
mFooterLayout = new RelativeLayout(parent.getContext());
}
baseViewHolder = BaseViewHolder.create(mFooterLayout);
break;
case TYPE_HEADER_VIEW:
baseViewHolder = BaseViewHolder.create(mHeaderLayout);
break;
}
return baseViewHolder;
}
...
然后就可以增加 HeaderView 了
...
/**
* 添加headerView
* @param view
* @param index
*/
public void addHeaderView(View view, int index) {
checkHeaderLayout(view);
int childCount = mHeaderLayout.getChildCount();
if (index < 0 || index > childCount) {
index = childCount;
}
mHeaderLayout.addView(view, index);
if (mHeaderLayout.getChildCount() == 1) {
notifyItemInserted(0);
}
}
private void checkHeaderLayout(View view) {
if (null == mHeaderLayout) {
mHeaderLayout = new LinearLayout(view.getContext());
mHeaderLayout.setOrientation(LinearLayout.VERTICAL);
mHeaderLayout.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
}
}
...
增加之前先检查下用来装 HederView 的 mHeaderLayout 是否创建,没有创建就创建出来并设置方向为竖向的,其实也可以设置成横向的,但是我还真没见过哪个 app 里有一个横向的列表还要在最左边放一个 header 的。
三、总体思路如下:
1.增加 headerView 时先在 itemCount 加 1,就是腾出一个 item 用来放 headerView;
2.getItemType 里增加 headerView 的判断,如果有 headerView 且 item 为第一个时,type 设置为 HEADER_TYPE;
3.在 onCreateViewHolder 里判断如果是 HEADER_TYPE 就创建 headerLayout 用来装 headerView,这样可以很方便的 add 多个 headerView。
到此就实现上面图中的效果了,有兴趣的可看完整源码。