RecyclerView正确添加Header
如何为RecyclerView添加Header
在Android开发中,经常会遇到列表页面,在使用Listview的时候,有专门的方法去添加header,但使用recyclerView的时候,无论是recyclerView还是LayoutManager都没有专门的方法去添加header,那如何给recyclerView添加header呢,网上有很多,最普遍的方法就是通过控制Adapter的itemType来设置的,思路就是根据不同的itemType去加载不同的布局。
public abstract class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.RecycleHolder> {
private Context mContext;
public List<T> mBodyDatas;
private int mBodyLayoutId, mHeaderLayoutId;
private LayoutInflater mInflater;
//item类型
public static final int ITEM_TYPE_HEADER = 0;//头
public static final int ITEM_TYPE_CONTENT = 1;//主体
private int mHeaderCount;//头部View个数
public OnItemClickListener onItemClickListener;//item监听
public RecyclerAdapter(Context mContext, List<T> mBodyDatas, int mBodyLayoutId) {
this(mContext, mBodyDatas, mBodyLayoutId, 0);
}
public RecyclerAdapter(Context mContext, List<T> mBodyDatas, int mBodyLayoutId, int mHeaderLayoutId) {
this.mContext = mContext;
this.mBodyDatas = mBodyDatas;
this.mBodyLayoutId = mBodyLayoutId;
this.mHeaderLayoutId = mHeaderLayoutId;
mInflater = LayoutInflater.from(mContext);
//判断是否有头
if (mHeaderLayoutId == 0) {
mHeaderCount = 0;
} else {
mHeaderCount = 1;
}
}
@NonNull
@Override
public RecycleHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_HEADER) {
return new RecycleHolder(mInflater.inflate(mHeaderLayoutId, parent, false));
} else if (viewType == ITEM_TYPE_CONTENT) {
return new RecycleHolder(mInflater.inflate(mBodyLayoutId, parent, false));
}
return null;
}
@Override
public void onBindViewHolder(@NonNull final RecyclerAdapter.RecycleHolder holder, int position) {
//根据item的类型实现与不同数据源进行衔接
if (isHeaderView(position)) {
convertHeader(holder, null, position);
} else {
convertBody(holder, mBodyDatas.get(position - mHeaderCount), position);
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//注意,这里的position不要用上面参数中的position,会出现位置错乱\
onItemClickListener.OnItemClickListener(holder.itemView, holder.getLayoutPosition() - mHeaderCount);
}
});
}
}
}
@Override
public int getItemCount() {
return mBodyDatas.size() + mHeaderCount;
}
/**
* 返回主体item的个数
*
* @return
*/
public int getContentItemCount() {
return mBodyDatas.size();
}
@Override
public int getItemViewType(int position) {
if (mHeaderCount != 0 && position < mHeaderCount) {
return ITEM_TYPE_HEADER;
}
return ITEM_TYPE_CONTENT;
}
/**
* 判断当前item是否是HeadView
*
* @param position
* @return
*/
public boolean isHeaderView(int position) {
return mHeaderCount != 0 && position < mHeaderCount;
}
/**
* 将主体数据源添加到主体上-----必须要重写
*
* @param holder
* @param data
* @param position
*/
public abstract void convertBody(RecycleHolder holder, T data, int position);
/**
* 将头部数据源添加到头部-----recyclerView添加头部时重写
*
* @param holder
* @param data
* @param position
*/
public void convertHeader(RecycleHolder holder, T data, int position) {
}
/**
* 为recycler View设置item的点击事件
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
//点击事件监听接口
public interface OnItemClickListener {
void OnItemClickListener(View view, int position);
}
public List<T> getmBodyDatas() {
return mBodyDatas;
}
public class RecycleHolder extends RecyclerView.ViewHolder {
/**
* 用于存储当前item当中的View
*/
private SparseArray<View> mViews;
public RecycleHolder(View itemView) {
super(itemView);
mViews = new SparseArray<View>();
}
public <T extends View> T findView(int ViewId) {
View view = mViews.get(ViewId);
//集合中没有,则从item当中获取,并存入集合当中
if (view == null) {
view = itemView.findViewById(ViewId);
mViews.put(ViewId, view);
}
return (T) view;
}
public RecycleHolder setText(int viewId, String text) {
TextView tv = findView(viewId);
tv.setText(text);
return this;
}
public RecycleHolder setText(int viewId, int text) {
TextView tv = findView(viewId);
tv.setText(text);
return this;
}
public RecycleHolder setImageResource(int viewId, int ImageId) {
ImageView image = findView(viewId);
image.setImageResource(ImageId);
return this;
}
public RecycleHolder setImageBitmap(int viewId, Bitmap bitmap) {
ImageView imageView = findView(viewId);
imageView.setImageBitmap(bitmap);
return this;
}
}
public void addDatas(List<T> lists) {
if (mBodyDatas == null) {
mBodyDatas = new ArrayList<>();
}
mBodyDatas.clear();
if (null == lists) {
return;
}
mBodyDatas.addAll(lists);
notifyDataSetChanged();
}
public void appendDatas(List<T> lists) {
if (null == lists) {
return;
}
if (mBodyDatas == null) {
mBodyDatas = new ArrayList<>();
}
mBodyDatas.addAll(lists);
notifyDataSetChanged();
}
}
这里重写了getItemViewType方法,并根据位置来返回不同的type,这个type是我们预先商定好的常量,接在onCreateViewHolder方法中来判断itemType,如果是header,则加载设置的header布局,否则正常加载item布局。
为GridLayoutManager添加header
最近公司再做一个项目,样式如下图
GridLayoutManager mgr = new GridLayoutManager(this, 2);
然后出现这么个玩意 ,和我们需求不一样啊,这时候我们就要去看源码和查资料了,发现有这么一个方法
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return getItemViewType(position) == ITEM_TYPE_HEADER
? gridManager.getSpanCount() : 1;
}
});
大致意思是当前位置是header时,占用你前面设置的单元格,其它的占用一个单元格,为了使用方便,在RecyclerAdapter中进行封装
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return getItemViewType(position) == ITEM_TYPE_HEADER
? gridManager.getSpanCount() : 1;
}
});
}
}
这时候,我们在跑一下我们的项目,就能实现我们的效果了。