之所以写这篇文章,是因为今天在面试的时候,被问到了。当然早在1年前,我就在项目中大量使用了RecyclerView。后来换了新的公司之后,就基本没怎么用了。没想到被面试官问了怎么添加header和footer,勉强答出来了。结果人家加了一句,如果LayoutManager是流式布局,或者GridLayoutManager的话,header会出现留白的问题,怎么处理啦?这个还真没用过,所以就干脆研究了一下。
private class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.Holder> {
private List<Integer> heightList;
//item类型
public static final int ITEM_TYPE_HEADER = 0;
public static final int ITEM_TYPE_CONTENT = 1;
public static final int ITEM_TYPE_FOOTER = 2;
public View getFooterView() {
return footerView;
}
public void setFooterView(View footerView) {
this.footerView = footerView;
}
public View getHeaderView() {
return headerView;
}
public void setHeaderView(View headerView) {
this.headerView = headerView;
}
private View headerView;
private View footerView;
public CustomAdapter() {
heightList = new ArrayList<>();
for(int i = 0; i < dataList.size(); i ++ ) {
heightList.add((int) (100 + Math.random()*300));
}
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
if(viewType == ITEM_TYPE_CONTENT) {
view = mInflater.inflate(R.layout.layout_item,null);
}else if(viewType == ITEM_TYPE_HEADER) {
view = headerView;
}else {
view = footerView;
}
return new Holder(view);
}
@Override
public void onBindViewHolder(Holder holder, int position) {
if(getItemViewType(position) == ITEM_TYPE_CONTENT) {
if(headerView != null) {
position -= 1;
}
int data = dataList.get(position);
holder.dataTXT.setText(data + "");
ViewGroup.LayoutParams params = holder.mLinearLayout.getLayoutParams();
params.height = heightList.get(position);
holder.mLinearLayout.setLayoutParams(params);
}
}
@Override
public void onViewAttachedToWindow(Holder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if(lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(holder.getItemViewType() == ITEM_TYPE_HEADER || holder.getItemViewType() == ITEM_TYPE_FOOTER);
}
}
@Override
public int getItemViewType(int position) {
if(headerView == null && footerView == null) {
return ITEM_TYPE_CONTENT;
}
if(position == 0 && headerView != null) {
return ITEM_TYPE_HEADER;
}else if(position == getItemCount() - 1 && footerView != null) {
return ITEM_TYPE_FOOTER;
}else {
return ITEM_TYPE_CONTENT;
}
}
@Override
public int getItemCount() {
return dataList.size() + (headerView == null ? 0 : 1) + (footerView == null ? 0 : 1);
}
class Holder extends RecyclerView.ViewHolder {
private LinearLayout mLinearLayout;
private TextView dataTXT;
public Holder(View itemView) {
super(itemView);
mLinearLayout = (LinearLayout) itemView.findViewById(R.id.lly);
dataTXT = (TextView) itemView.findViewById(R.id.data_txt);
}
}
}
上面这段代码,关键的地方在getItemViewType(int position)这个方法中,正常情况下,我们是不需要重写这个方法的。当我们需要给RecyclerView添加header或者footer的时候,就需要用到这个方法了。可以看到在自定义Adapter时,我们定义了3个字段分别代表item的3种类型:ITEM_TYPE_HEADER、ITEM_TYPE_FOOTER、ITEM_TYPE_CONTENT。在这个方法里面,我们通过position来判断,当position=0时,就返回ITEM_TYPE_HEADER代表头视图,当position=getItemCount() - 1时,就返回ITEM_TYPE_FOOTER代表尾视图,其他则返回ITEM_TYPE_CONTENT,代表是普通的item视图。
然后我们在onCreateViewHolder()方法中,根据ViewType来判断应该传入哪一种布局。
这样我们添加header和footer的问题就解决了。但是正常情况下,我们在项目中的头布局和尾部局肯定都是单独占一行,这个我们要怎么解决啦?
要解决这个问题,我们就需要去重写onViewAttachedToWindow()这个方法了。
@Override
public void onViewAttachedToWindow(Holder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if(lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
p.setFullSpan(holder.getItemViewType() == ITEM_TYPE_HEADER || holder.getItemViewType() == ITEM_TYPE_FOOTER);
}
}
这里我们获取itemview的layoutparams,然后调用setFullSpan来让它占满全整行空间。就可以达到我们想要的效果啦!
部分参考:http://blog.csdn.net/qibin0506/article/details/49716795