安卓笔记侠

专注安卓开发

导航

RecyclerView--添加头部和底部

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     @Override
106     public int getItemViewType(int position) {
107         if (isHeaderPosition(position)) {
108             // 直接返回position位置的key
109             return mHeaderViews.keyAt(position);
110         }
111         if (isFooterPosition(position)) {
112             // 直接返回position位置的key
113             position = position - mHeaderViews.size() - mAdapter.getItemCount();
114             return mFooterViews.keyAt(position);
115         }
116         // 返回列表Adapter的getItemViewType
117         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     @Override
136     public int getItemCount() {
137         // 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数
138         return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();
139     }
140 
141     /**
142      * 获取列表的Adapter
143      */
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 recycler
186      * @version 1.0
187      */
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                 @Override
193                 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         @Override
107         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         @Override
116         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         @Override
125         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         @Override
134         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         @Override
143         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     @Override
32     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         @Override
43         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 }

 

posted on 2018-01-12 13:54  安卓笔记侠  阅读(7241)  评论(0编辑  收藏  举报