给RecyclerView添加header和footer
在最近的项目中,需要用到recyclerview添加header和footer来实现一些效果,想了想最基本的就是重写adapter的getItemViewType的方法来实现。但由于时间问题,加上博主比较懒。。。就找了个开源库,大家可能用过,叫bookends。这里就不贴地址了,本文讲的就是对bookend的改进,来实现更好的效果。
项目中需要用到header,footer的动态显示隐藏,本以为很简单的事,使用时却出了问题。
这里是正常状态的效果,从用户发布以上是一个header,搜索实现从网络获取数据和从自家数据库获取数据,此时自家数据库是没数据的,recyclerview显示为空。而网络搜索显示有结果,显示在header。
可是当网络搜索结果为空时,问题出现了。
如图所示,header被隐藏了,可是占用的位置却没有消失。我调用的是bookends的setHeaderVisibility方法,于是查看源码
public void setHeaderVisibility(boolean shouldShow) {
for (View header : mHeaders) {
header.setVisibility(shouldShow ? View.VISIBLE : View.GONE);
}
}
看起来没有问题,逻辑什么的都正确,GONE后的布局不占用空间位置。找不到问题就只能靠自己了。
public void removeAllHeaders() {
mHeaders = new ArrayList<>();
notifyDataSetChanged();
}
public void removeAllFooters() {
mFooters = new ArrayList<>();
notifyDataSetChanged();
}
public void removeHeader(int position) {
if (position < mHeaders.size())
mHeaders.remove(position);
notifyDataSetChanged();
}
public void removeFooter(int position) {
if (position < mHeaders.size())
mFooters.remove(position);
notifyDataSetChanged();
}
当当当当,问题解决。写了四个函数。测试了下 可以动态改变header和footer了。
源代码:
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Created by simple on 2016/12/9.
*/
public class Bookends<T extends RecyclerView.Adapter> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final T mBase;
private static final int HEADER_VIEW_TYPE = -1000;
private static final int FOOTER_VIEW_TYPE = -2000;
private List<View> mHeaders = new ArrayList<View>();
private List<View> mFooters = new ArrayList<View>();
public Bookends(T base) {
super();
mBase = base;
}
public T getWrappedAdapter() {
return mBase;
}
public void addHeader(@NonNull View view) {
if (view == null) {
throw new IllegalArgumentException("You can't have a null header!");
}
mHeaders.add(view);
notifyDataSetChanged();
}
public void addFooter(@NonNull View view) {
if (view == null) {
throw new IllegalArgumentException("You can't have a null footer!");
}
mFooters.add(view);
notifyDataSetChanged();
}
public void removeAllHeaders() {
mHeaders = new ArrayList<>();
notifyDataSetChanged();
}
public void removeAllFooters() {
mFooters = new ArrayList<>();
notifyDataSetChanged();
}
public void removeHeader(int position) {
if (position < mHeaders.size())
mHeaders.remove(position);
notifyDataSetChanged();
}
public void removeFooter(int position) {
if (position < mHeaders.size())
mFooters.remove(position);
notifyDataSetChanged();
}
public View getHeader(int i) {
return i < mHeaders.size() ? mHeaders.get(i) : null;
}
public View getFooter(int i) {
return i < mFooters.size() ? mFooters.get(i) : null;
}
private boolean isHeader(int viewType) {
return viewType >= HEADER_VIEW_TYPE && viewType < (HEADER_VIEW_TYPE + mHeaders.size());
}
private boolean isFooter(int viewType) {
return viewType >= FOOTER_VIEW_TYPE && viewType < (FOOTER_VIEW_TYPE + mFooters.size());
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (isHeader(viewType)) {
int whichHeader = Math.abs(viewType - HEADER_VIEW_TYPE);
View headerView = mHeaders.get(whichHeader);
return new RecyclerView.ViewHolder(headerView) {
};
} else if (isFooter(viewType)) {
int whichFooter = Math.abs(viewType - FOOTER_VIEW_TYPE);
View footerView = mFooters.get(whichFooter);
return new RecyclerView.ViewHolder(footerView) {
};
} else {
return mBase.onCreateViewHolder(viewGroup, viewType);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (position < mHeaders.size()) {
// Headers don't need anything special
} else if (position < mHeaders.size() + mBase.getItemCount()) {
// This is a real position, not a header or footer. Bind it.
mBase.onBindViewHolder(viewHolder, position - mHeaders.size());
} else {
// Footers don't need anything special
}
}
@Override
public int getItemCount() {
return mHeaders.size() + mBase.getItemCount() + mFooters.size();
}
@Override
public int getItemViewType(int position) {
if (position < mHeaders.size()) {
return HEADER_VIEW_TYPE + position;
} else if (position < (mHeaders.size() + mBase.getItemCount())) {
return mBase.getItemViewType(position - mHeaders.size());
} else {
return FOOTER_VIEW_TYPE + position - mHeaders.size() - mBase.getItemCount();
}
}
}
使用方法:
将自己的adapter放入。
Bookends bookends= new Bookends<>(adapter);
添加footer和header
bookends.addHeader(header);
bookends.addFooter(footer);
为recyclerview设置adapter
RecyclerView.setAdapter(bookends);