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 }