為recyclerView添加header和footer也是我們在開發(fā)過程中經(jīng)常遇見的,實(shí)現(xiàn)起來也是比較簡單的廷粒。下面介紹怎么添加header和footer
其實(shí)我們可以將header和footer看做是特殊的item泪幌,在添加他之后肴焊,我們值需要對(duì)他進(jìn)行一些特殊的處理就可以達(dá)到我們想到的效果其屏。
為了簡單起見,我們直接在adapter中進(jìn)行這一部分的操作措译。
在adapter中新建一些標(biāo)識(shí)的int值别凤,用于區(qū)分是否需要添加header和footer,如下所示:
public static final int TYPE_HEADER = 0; //說明是帶有Header的
public static final int TYPE_FOOTER = 1; //說明是帶有Footer的
public static final int TYPE_NORMAL = 2; //說明是不帶有header和footer的
對(duì)外暴露添加header和footer方法领虹,參考如下:
private View mHeaderView;
private View mFooterView;
public void setHeaderView(View headerView) {
mHeaderView = headerView;
notifyItemInserted(0);
}
public void setFooterView(View footerView) {
mFooterView = footerView;
notifyItemInserted(getItemCount() - 1);
}
覆寫getItemViewType()方法规哪,用于區(qū)分是否需要添加head和footer
@Override
public int getItemViewType(int position) {
if (mHeaderView == null && mFooterView == null) {
return TYPE_NORMAL;
}
if (position == 0) {
return TYPE_HEADER;
}
if (position == getItemCount() - 1) {
return TYPE_FOOTER;
}
return TYPE_NORMAL;
}
在onCreateViewHolder中添加對(duì)header和footer的支持
if (mHeaderView != null && viewType == TYPE_HEADER) {
return new ItemHolder(mHeaderView);
}
if (mFooterView != null && viewType == TYPE_FOOTER) {
return new ItemHolder(mFooterView);
}
在onBindViewHolder增加對(duì)header和footer的處理,如果當(dāng)前對(duì)象是header或者footer直接返回即可塌衰。
如果有header的話诉稍,因?yàn)閔eader也需要占一個(gè)位子,所以顯示的時(shí)候需要顯示當(dāng)前位子的前一個(gè)位子最疆。
if (getItemViewType(position) == TYPE_HEADER) return;
else if (getItemViewType(position) == TYPE_FOOTER) return;
else {
if (holder instanceof MyAdapterWith.ItemHolder) {
position = holder.getLayoutPosition();
position = mHeaderView == null ? position : position - 1;
//計(jì)算當(dāng)前的位置杯巨,如果添加了header的話,header也需要占用一個(gè)位置
if (position < datas.size()) {
holder.imageView.setImageResource(datas.get(position).getId());
holder.teTitle.setText(datas.get(position).getTitle());
holder.teContent.setText(datas.get(position).getContent());
}
}
}
然后努酸,需要在ViewHolder中添加對(duì)header和footer的支持
public class ItemHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView teTitle;
public TextView teContent;
public ItemHolder(View itemView) {
super(itemView);
if (itemView == mHeaderView)
return;
if (itemView == mFooterView)
return;
imageView = (ImageView) itemView.findViewById(R.id.item_image);
teTitle = (TextView) itemView.findViewById(R.id.item_title);
teContent = (TextView) itemView.findViewById(R.id.item_content);
}
最后服爷,我們就可以直接在activity中進(jìn)行添加了
View view = LayoutInflater.from(this).inflate(R.layout.head,mRecyclerView,false);
mMyAdapter.setHeaderView(view);
View footer = LayoutInflater.from(this).inflate(R.layout.foot,mRecyclerView,false);
mMyAdapter.setFooterView(footer);
其中R.layout.head
和R.layout.foot
是head和foot的布局。
當(dāng)然获诈。這樣寫好之后仍源,我們可以觀察到這樣的結(jié)果:
基本正常,但是當(dāng)我們使用GridLayoutManager時(shí)舔涎,會(huì)發(fā)現(xiàn)這樣的問題笼踩。
可以看到,這里我們的header和footer被當(dāng)作一個(gè)item终抽,并沒有實(shí)現(xiàn)我們想到的置頂占行的效果戳表。
解決方案:
利用GridLayoutManager的setSpanSizeLookup方法:
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (getItemViewType(position) == TYPE_HEADER || getItemViewType(position) == TYPE_FOOTER)
return gridLayoutManager.getSpanCount();
else
return 1;
}
});
這里的getSpanSize()方法返回的值決定了每個(gè)position上item占據(jù)的單元格個(gè)數(shù)。為了簡單起見昼伴,可以將這個(gè)方法放在adapter中匾旭。代碼如下:
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager==null) Log.d("TAG", "manager=null");
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (getItemViewType(position) == TYPE_HEADER || getItemViewType(position) == TYPE_FOOTER)
return gridLayoutManager.getSpanCount();
else
return 1;
}
});
}
}
最后,再為StaggeredGridLayoutManager做一些處理圃郊。
@Override
public void onViewAttachedToWindow(ItemHolder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if (lp != null
&& lp instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
if (mHeaderView != null)
p.setFullSpan(holder.getLayoutPosition() == 0);
// if(mFooterView!=null)
// p.setFullSpan(holder.getLayoutPosition() ==datas.size());
}
}
到此价涝,添加header和footer的基本操作就完成了。不過在日常使用中持舆,我們肯定會(huì)對(duì)每一次都需要編寫一個(gè)這么復(fù)雜的header類感覺很麻煩色瘩,這里可以考慮封裝一下。
對(duì)了逸寓,在使用的過程中居兆,如果需要適配GridLayoutManager的話,在activity的recycler的setAdapter方法之前竹伸,需要先調(diào)用 mRecyclerView.setLayoutManager(mManager);
參見代碼:
RecyclerView.LayoutManager mManager = new new GridLayoutManager(this,2);
mRecyclerView.setLayoutManager(mManager);
mRecyclerView.setAdapter(mMyAdapter);
如果這樣寫:
RecyclerView.LayoutManager mManager = new new GridLayoutManager(this,2);
mRecyclerView.setAdapter(mMyAdapter);
mRecyclerView.setLayoutManager(mManager);
那么泥栖,我們在adapter中編寫的對(duì)GridLayoutManager的適配就無法獲取到recycler而無法起作用簇宽。