RecyclerView--添加头部和底部

2018-01-12 21:18:08来源:cnblogs.com作者:ganchuanpu人点击

分享

1.先构建WrapRecyclerAdapter

  1 /**  2  * Description: 可以添加头部和底部的Adapter  3  */  4 public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  5     private final static String TAG = "WrapRecyclerAdapter";  6   7     /**  8      * SparseArrays map integers to Objects.  Unlike a normal array of Objects,  9      * there can be gaps in the indices.  It is intended to be more memory efficient 10      * than using a HashMap to map Integers to Objects, both because it avoids 11      * auto-boxing keys and its data structure doesn't rely on an extra entry object 12      * for each mapping. 13      * 14      * SparseArray是一个<int , Object>的HashMap  比HashMap更高效 15      */ 16     private SparseArray<View> mHeaderViews; 17     private SparseArray<View> mFooterViews; 18  19     // 基本的头部类型开始位置  用于viewType 20     private static int BASE_ITEM_TYPE_HEADER = 10000000; 21     // 基本的底部类型开始位置  用于viewType 22     private static int BASE_ITEM_TYPE_FOOTER = 20000000; 23  24     /** 25      * 数据列表的Adapter 26      */ 27     private RecyclerView.Adapter mAdapter; 28  29     public WrapRecyclerAdapter(RecyclerView.Adapter adapter) { 30         this.mAdapter = adapter; 31         mHeaderViews = new SparseArray<>(); 32         mFooterViews = new SparseArray<>(); 33     } 34  35     @Override 36     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 37  38         // viewType 可能就是 SparseArray 的key 39         if (isHeaderViewType(viewType)) { 40             View headerView = mHeaderViews.get(viewType); 41             return createHeaderFooterViewHolder(headerView); 42         } 43  44         if (isFooterViewType(viewType)) { 45             View footerView = mFooterViews.get(viewType); 46             return createHeaderFooterViewHolder(footerView); 47         } 48         return mAdapter.onCreateViewHolder(parent, viewType); 49     } 50  51     /** 52      * 是不是底部类型 53      */ 54     private boolean isFooterViewType(int viewType) { 55         int position = mFooterViews.indexOfKey(viewType); 56         return position >= 0; 57     } 58  59     /** 60      * 创建头部或者底部的ViewHolder 61      */ 62     private RecyclerView.ViewHolder createHeaderFooterViewHolder(View view) { 63         return new RecyclerView.ViewHolder(view) { 64  65         }; 66     } 67  68     /** 69      * 是不是头部类型 70      */ 71     private boolean isHeaderViewType(int viewType) { 72         int position = mHeaderViews.indexOfKey(viewType); 73         return position >= 0; 74     } 75  76     @Override 77     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 78         if (isHeaderPosition(position) || isFooterPosition(position)) { 79             return; 80         } 81  82         // 计算一下位置 83         final int adapterPosition = position - mHeaderViews.size(); 84         mAdapter.onBindViewHolder(holder, adapterPosition); 85  86         // 设置点击和长按事件 87         if (mItemClickListener != null) { 88             holder.itemView.setOnClickListener(new View.OnClickListener() { 89                 @Override 90                 public void onClick(View v) { 91                     mItemClickListener.onItemClick(v, adapterPosition); 92                 } 93             }); 94         } 95         if (mLongClickListener != null) { 96             holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 97                 @Override 98                 public boolean onLongClick(View v) { 99                     return mLongClickListener.onLongClick(v, adapterPosition);100                 }101             });102         }103     }104 105     @Override106     public int getItemViewType(int position) {107         if (isHeaderPosition(position)) {108             // 直接返回position位置的key109             return mHeaderViews.keyAt(position);110         }111         if (isFooterPosition(position)) {112             // 直接返回position位置的key113             position = position - mHeaderViews.size() - mAdapter.getItemCount();114             return mFooterViews.keyAt(position);115         }116         // 返回列表Adapter的getItemViewType117         position = position - mHeaderViews.size();118         return mAdapter.getItemViewType(position);119     }120 121     /**122      * 是不是底部位置123      */124     private boolean isFooterPosition(int position) {125         return position >= (mHeaderViews.size() + mAdapter.getItemCount());126     }127 128     /**129      * 是不是头部位置130      */131     private boolean isHeaderPosition(int position) {132         return position < mHeaderViews.size();133     }134 135     @Override136     public int getItemCount() {137         // 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数138         return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();139     }140 141     /**142      * 获取列表的Adapter143      */144     private RecyclerView.Adapter getAdapter() {145         return mAdapter;146     }147 148     // 添加头部149     public void addHeaderView(View view) {150         int position = mHeaderViews.indexOfValue(view);151         if (position < 0) {152             mHeaderViews.put(BASE_ITEM_TYPE_HEADER++, view);153         }154         notifyDataSetChanged();155     }156 157     // 添加底部158     public void addFooterView(View view) {159         int position = mFooterViews.indexOfValue(view);160         if (position < 0) {161             mFooterViews.put(BASE_ITEM_TYPE_FOOTER++, view);162         }163         notifyDataSetChanged();164     }165 166     // 移除头部167     public void removeHeaderView(View view) {168         int index = mHeaderViews.indexOfValue(view);169         if (index < 0) return;170         mHeaderViews.removeAt(index);171         notifyDataSetChanged();172     }173 174     // 移除底部175     public void removeFooterView(View view) {176         int index = mFooterViews.indexOfValue(view);177         if (index < 0) return;178         mFooterViews.removeAt(index);179         notifyDataSetChanged();180     }181 182     /**183      * 解决GridLayoutManager添加头部和底部不占用一行的问题184      *185      * @param recycler186      * @version 1.0187      */188     public void adjustSpanSize(RecyclerView recycler) {189         if (recycler.getLayoutManager() instanceof GridLayoutManager) {190             final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();191             layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {192                 @Override193                 public int getSpanSize(int position) {194                     boolean isHeaderOrFooter =195                             isHeaderPosition(position) || isFooterPosition(position);196                     return isHeaderOrFooter ? layoutManager.getSpanCount() : 1;197                 }198             });199         }200     }201 202     /***************203      * 给条目设置点击和长按事件204      *********************/205     public OnItemClickListener mItemClickListener;206     public OnLongClickListener mLongClickListener;207 208     public void setOnItemClickListener(OnItemClickListener itemClickListener) {209         this.mItemClickListener = itemClickListener;210     }211 212     public void setOnLongClickListener(OnLongClickListener longClickListener) {213         this.mLongClickListener = longClickListener;214     }215 }

2.构建WrapRecyclerView

我们最好还是模仿ListView的结构搞就搞到西,自定义一个WrapRecyclerView,可以添加删除头部和底部View,这个就比较简单

  1 /**  2  * Description: 可以添加头部和底部的RecyclerView  3  */  4 public class WrapRecyclerView extends RecyclerView {  5     // 包裹了一层的头部底部Adapter  6     private WrapRecyclerAdapter mWrapRecyclerAdapter;  7     // 这个是列表数据的Adapter  8     private Adapter mAdapter;  9  10     // 增加一些通用功能 11     // 空列表数据应该显示的空View 12     // 正在加载数据页面,也就是正在获取后台接口页面 13     private View mEmptyView, mLoadingView; 14  15     public WrapRecyclerView(Context context) { 16         super(context); 17     } 18  19     public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) { 20         super(context, attrs); 21     } 22  23     public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 24         super(context, attrs, defStyle); 25     } 26  27     @Override 28     public void setAdapter(Adapter adapter) { 29         // 为了防止多次设置Adapter 30         if (mAdapter != null) { 31             mAdapter.unregisterAdapterDataObserver(mDataObserver); 32             mAdapter = null; 33         } 34  35         this.mAdapter = adapter; 36  37         if (adapter instanceof WrapRecyclerAdapter) { 38             mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter; 39         } else { 40             mWrapRecyclerAdapter = new WrapRecyclerAdapter(adapter); 41         } 42  43         super.setAdapter(mWrapRecyclerAdapter); 44  45         // 注册一个观察者 46         mAdapter.registerAdapterDataObserver(mDataObserver); 47  48         // 解决GridLayout添加头部和底部也要占据一行 49         mWrapRecyclerAdapter.adjustSpanSize(this); 50  51         // 加载数据页面 52         if (mLoadingView != null && mLoadingView.getVisibility() == View.VISIBLE) { 53             mLoadingView.setVisibility(View.GONE); 54         } 55  56         if (mItemClickListener != null) { 57             mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener); 58         } 59  60         if (mLongClickListener != null) { 61             mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener); 62         } 63     } 64  65     // 添加头部 66     public void addHeaderView(View view) { 67         // 如果没有Adapter那么就不添加,也可以选择抛异常提示 68         // 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式 69         if (mWrapRecyclerAdapter != null) { 70             mWrapRecyclerAdapter.addHeaderView(view); 71         } 72     } 73  74     // 添加底部 75     public void addFooterView(View view) { 76         if (mWrapRecyclerAdapter != null) { 77             mWrapRecyclerAdapter.addFooterView(view); 78         } 79     } 80  81     // 移除头部 82     public void removeHeaderView(View view) { 83         if (mWrapRecyclerAdapter != null) { 84             mWrapRecyclerAdapter.removeHeaderView(view); 85         } 86     } 87  88     // 移除底部 89     public void removeFooterView(View view) { 90         if (mWrapRecyclerAdapter != null) { 91             mWrapRecyclerAdapter.removeFooterView(view); 92         } 93     } 94  95     private AdapterDataObserver mDataObserver = new AdapterDataObserver() { 96         @Override 97         public void onChanged() { 98             if (mAdapter == null) return; 99             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果100             if (mWrapRecyclerAdapter != mAdapter)101                 mWrapRecyclerAdapter.notifyDataSetChanged();102 103             dataChanged();104         }105 106         @Override107         public void onItemRangeRemoved(int positionStart, int itemCount) {108             if (mAdapter == null) return;109             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果110             if (mWrapRecyclerAdapter != mAdapter)111                 mWrapRecyclerAdapter.notifyItemRemoved(positionStart);112             dataChanged();113         }114 115         @Override116         public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {117             if (mAdapter == null) return;118             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果119             if (mWrapRecyclerAdapter != mAdapter)120                 mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);121             dataChanged();122         }123 124         @Override125         public void onItemRangeChanged(int positionStart, int itemCount) {126             if (mAdapter == null) return;127             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果128             if (mWrapRecyclerAdapter != mAdapter)129                 mWrapRecyclerAdapter.notifyItemChanged(positionStart);130             dataChanged();131         }132 133         @Override134         public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {135             if (mAdapter == null) return;136             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果137             if (mWrapRecyclerAdapter != mAdapter)138                 mWrapRecyclerAdapter.notifyItemChanged(positionStart, payload);139             dataChanged();140         }141 142         @Override143         public void onItemRangeInserted(int positionStart, int itemCount) {144             if (mAdapter == null) return;145             // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果146             if (mWrapRecyclerAdapter != mAdapter)147                 mWrapRecyclerAdapter.notifyItemInserted(positionStart);148             dataChanged();149         }150     };151 152     /**153      * 添加一个空列表数据页面154      */155     public void addEmptyView(View emptyView) {156         this.mEmptyView = emptyView;157     }158 159     /**160      * 添加一个正在加载数据的页面161      */162     public void addLoadingView(View loadingView) {163         this.mLoadingView = loadingView;164         mLoadingView.setVisibility(View.VISIBLE);165     }166 167     /**168      * Adapter数据改变的方法169      */170     private void dataChanged() {171         if (mAdapter.getItemCount() == 0) {172             // 没有数据173             if (mEmptyView != null) {174                 mEmptyView.setVisibility(VISIBLE);175             }176         } else {177             // 没有数据178             if (mEmptyView != null) {179                 mEmptyView.setVisibility(GONE);180             }181         }182     }183 184     /***************185      * 给条目设置点击和长按事件186      *********************/187     public com.zzw.framelibray.recyclerview.adapter.OnItemClickListener mItemClickListener;188     public com.zzw.framelibray.recyclerview.adapter.OnLongClickListener mLongClickListener;189 190     public void setOnItemClickListener(com.zzw.framelibray.recyclerview.adapter.OnItemClickListener itemClickListener) {191         this.mItemClickListener = itemClickListener;192 193         if (mWrapRecyclerAdapter != null) {194             mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener);195         }196     }197 198     public void setOnLongClickListener(com.zzw.framelibray.recyclerview.adapter.OnLongClickListener longClickListener) {199         this.mLongClickListener = longClickListener;200 201         if (mWrapRecyclerAdapter != null) {202             mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener);203         }204     }205 }

3.使用:

 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:orientation="vertical" android:layout_width="match_parent" 4     android:layout_height="match_parent"> 5  6     <com.zzw.framelibray.recyclerview.view.WrapRecyclerView 7         android:id="@+id/wrap_recycler_view" 8         android:layout_width="match_parent" 9         android:layout_height="match_parent"10 11         />12 13 </LinearLayout>
Activity
 1 public class HeaderFooterActivity extends AppCompatActivity implements OnItemClickListener { 2  3     private WrapRecyclerView mRecyclerView; 4     private List<People> mData; 5  6     @Override 7     protected void onCreate(Bundle savedInstanceState) { 8         super.onCreate(savedInstanceState); 9         setContentView(R.layout.activity_recycler_view);10         mRecyclerView = (WrapRecyclerView) findViewById(R.id.wrap_recycler_view);11         mRecyclerView.setLayoutManager(new LinearLayoutManager(this));12 13         mData =new ArrayList<>();14         mData.add(new People());15         mData.add(new People());16         mData.add(new People());17 18         PeopleListAdapter listAdapter = new PeopleListAdapter(this, mData);19 20         // 添加头部和底部 需要 包裹Adapter,才能添加头部和底部21         WrapRecyclerAdapter wrapRecyclerAdapter = new WrapRecyclerAdapter(listAdapter);22         mRecyclerView.setAdapter(wrapRecyclerAdapter);23 24         wrapRecyclerAdapter.setOnItemClickListener(this);25 26         // 添加头部和底部27         wrapRecyclerAdapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false));28         wrapRecyclerAdapter.addFooterView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false));29     }30 31     @Override32     public void onItemClick(View view, int position) {33         Toast.makeText(this, "" + mData.get(position).name, Toast.LENGTH_SHORT).show();34     }35 36     class PeopleListAdapter extends CommonRecyclerAdapter<People> {37 38         public PeopleListAdapter(Context context, List<People> datas) {39             super(context, datas, R.layout.channel_list_item);40         }41 42         @Override43         public void convert(ViewHolder holder, People item, int position) {44             holder.setText(R.id.action_btn, item.name+position);45         }46     }47 48     class People{49         String name="王伟:";50     }51 }

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台