基于前面的博文给RecyclerView添加Header,给RecyclerView添加多个Header
通过上节的内容,我们知道了给RecyclerView(GridLayoutManager)添加Header的方法
1.首先初始化了一个HeaderView用于下拉刷新使用并且将这个下拉刷新的布局添加到头布局
/** * 初始化头布局 */ private void initHeaderView() { header = RecyclerViewHeader.fromXml(getContext(), R.layout.refresh_header); // 添加HeaderView this.addHeaderView(header); tvTitle = (TextView) header.findViewById(R.id.tv_title); tvTime = (TextView) header.findViewById(R.id.tv_time); ivArrow = (ImageView) header.findViewById(R.id.iv_arr); pbProgress = (ProgressBar) header.findViewById(R.id.pb_progress); header.measure(0, 0); headerHeight = header.getMeasuredHeight(); // 隐藏头布局 header.setPadding(0, -headerHeight, 0, 0); // 负的值就能够让控件向上移动了 initArrowAnim(); // 初始化箭头动画 // 更新最后刷新的时间 tvTime.setText("最后刷新时间" + getCurrentTime()); }
2.在添加头布局的时候,首先先是将原先拥有的HeaderView全部都清除了,接着再将需要添加的View添加进去,值得注意的是,就是这个clear操作导致了我们自己自定义的addHeaderView方法只能够添加一个HeaderView
/** * 添加头布局 * * @param view */ public void addHeaderView(View view) { mHeaderViews.clear(); mHeaderViews.add(view); if (mAdapter != null) { if (!(mAdapter instanceof RecyclerWrapAdapter)) { mAdapter = new RecyclerWrapAdapter(mHeaderViews, mFooterViews, mAdapter); mAdapter.notifyDataSetChanged(); } } }
3.在addHeaderView中实例化RecyclerWrapAdapter,这个RecyclerWrapAdapter就是整个自定义RecyclerView中最核心的部分,我们挑选最重要的地方来看
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); }
@Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 }
这两段代码就是最重要的地方,我们会发现,getViewType返回的值被引用成了onCreateViewHolder的参数所以我们如果想要添加多个HeaderView就需要在这里入手。
添加多个HeaderView的具体方法:
1.我们将RecyclerWrapAdapter中的核心方法修改下,修改成可以添加两个HeaderView的
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if(viewType == RecyclerView.INVALID_TYPE - 1){ return new HeaderViewHolder(mHeaderViews.get(1)); // 将第二个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); }
@Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { if (position != mCurrentPosition) { // 这是第二个HeaderView return RecyclerView.INVALID_TYPE - 1; // 这是第二个HeaderView所占用的空间 } return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 }
2.光在RecyclerWrapAdapter里改还不够,还记得addHeaderView方法的第一行代码mHeaderView.clear();这段代码就从源头上将添加多个HeaderVIew的源头给堵住了,所以,如果我们需要添加多个HeaderView就需要将这段代码删掉。
// mHeaderViews.clear();
然后再运行下,就可以发现两个HeaderView就成功添加了!
下面附上RecyclerWrapAdapter 的源码:
package com.deltalab.urecommend.adapter.friend_pager; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import com.deltalab.urecommend.adapter.base.WrapperAdapter; import java.util.ArrayList; /** * Created by asus on 2016/10/14. * 添加了headerView和footerView的布局适配器 * 模仿ListView里addHeader的HeaderViewListAdapter * * @author Administrator * @time 2016/10/14 16:54 */ public class RecyclerWrapAdapter extends RecyclerView.Adapter implements WrapperAdapter { private RecyclerView.Adapter mAdapter; private ArrayList<View> mHeaderViews; private ArrayList<View> mFooterViews; private int mCurrentPosition = -1; static final ArrayList<View> EMPTY_INFO_LIST = new ArrayList<View>(); public RecyclerWrapAdapter(ArrayList<View> mHeaderViews, ArrayList<View> mFooterViews, RecyclerView.Adapter mAdapter) { this.mAdapter = mAdapter; if (mHeaderViews == null) { this.mHeaderViews = EMPTY_INFO_LIST; } else { this.mHeaderViews = mHeaderViews; } if (mFooterViews == null) { this.mFooterViews = EMPTY_INFO_LIST; } else { this.mFooterViews = mFooterViews; } } /** * 获取头布局的数量 * * @return */ public int getHeadersCount() { return mHeaderViews.size(); } public int getFootersCount() { return mFooterViews.size(); } /** * 把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例 * 如果是Header、Footer则使用HeaderViewHolder封装 * 如果是其他的就不变 * * @param parent * @param viewType * @return */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == RecyclerView.INVALID_TYPE) { return new HeaderViewHolder(mHeaderViews.get(0)); // 将第一个HeaderView封装 } else if(viewType == RecyclerView.INVALID_TYPE - 1){ return new HeaderViewHolder(mHeaderViews.get(1)); // 将第二个HeaderView封装 } else if (viewType == RecyclerView.INVALID_TYPE - 2) { return new HeaderViewHolder(mFooterViews.get(0)); // 将FooterView封装 } return mAdapter.onCreateViewHolder(parent, viewType); } /** * 用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。 * * @param holder * @param position */ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { // Header int numHeaders = getHeadersCount(); if (position < numHeaders) { return; } // Adapter int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { mAdapter.onBindViewHolder(holder, adjPosition); return; } } } /** * 将Header、Footer挂靠到RecyclerView * * @param recyclerView */ @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { // 布局是GridLayoutManager所管理 final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager; gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { // 如果是Header、Footer的对象则占据spanCount的位置,否则就只占用1个位置 return (isHeader(position) || isFooter(position)) ? gridLayoutManager .getSpanCount() : 1; } }); } } /** * 判断是否是Header的位置 * 如果是Header的则返回true否则返回false * * @param position * @return */ public boolean isHeader(int position) { return position >= 0 && position < mHeaderViews.size(); } /** * 判断是否是Footer的位置 * 如果是Footer的位置则返回true否则返回false * * @param position * @return */ public boolean isFooter(int position) { return position < getItemCount() && position >= getItemCount() - mFooterViews.size(); } @Override public int getItemCount() { if (mAdapter != null) { return getHeadersCount() + getFootersCount() + mAdapter.getItemCount(); } else { return getHeadersCount() + getFootersCount(); } } @Override public int getItemViewType(int position) { if (mCurrentPosition == -1) { mCurrentPosition = position; // 这是第一个HeaderView } int numHeaders = getHeadersCount(); if (position < numHeaders) { if (position != mCurrentPosition) { // 这是第二个HeaderView return RecyclerView.INVALID_TYPE - 1; // 这是第二个HeaderView所占用的空间 } return RecyclerView.INVALID_TYPE; // 这是第一个HeaderView所占用的空间 } int adjPosition = position - numHeaders; int adapterCount = 0; if (mAdapter != null) { adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemViewType(adjPosition); } } return RecyclerView.INVALID_TYPE - 2; // 说明是Footer的所占用的空间 } @Override public long getItemId(int position) { int numHeaders = getHeadersCount(); if (mAdapter != null && position >= numHeaders) { int adjPosition = position - numHeaders; int adapterCount = mAdapter.getItemCount(); if (adjPosition < adapterCount) { return mAdapter.getItemId(adjPosition); // 不是Header和Footer则返回其itemId } } return -1; } @Override public RecyclerView.Adapter getWrapperAdapter() { return mAdapter; } private static class HeaderViewHolder extends RecyclerView.ViewHolder { public HeaderViewHolder(View itemView) { super(itemView); } } }