1.先构建WrapRecyclerAdapter

 /**
* Description: 可以添加头部和底部的Adapter
*/
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final static String TAG = "WrapRecyclerAdapter"; /**
* SparseArrays map integers to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more memory efficient
* than using a HashMap to map Integers to Objects, both because it avoids
* auto-boxing keys and its data structure doesn't rely on an extra entry object
* for each mapping.
*
* SparseArray是一个<int , Object>的HashMap 比HashMap更高效
*/
private SparseArray<View> mHeaderViews;
private SparseArray<View> mFooterViews; // 基本的头部类型开始位置 用于viewType
private static int BASE_ITEM_TYPE_HEADER = ;
// 基本的底部类型开始位置 用于viewType
private static int BASE_ITEM_TYPE_FOOTER = ; /**
* 数据列表的Adapter
*/
private RecyclerView.Adapter mAdapter; public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
this.mAdapter = adapter;
mHeaderViews = new SparseArray<>();
mFooterViews = new SparseArray<>();
} @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // viewType 可能就是 SparseArray 的key
if (isHeaderViewType(viewType)) {
View headerView = mHeaderViews.get(viewType);
return createHeaderFooterViewHolder(headerView);
} if (isFooterViewType(viewType)) {
View footerView = mFooterViews.get(viewType);
return createHeaderFooterViewHolder(footerView);
}
return mAdapter.onCreateViewHolder(parent, viewType);
} /**
* 是不是底部类型
*/
private boolean isFooterViewType(int viewType) {
int position = mFooterViews.indexOfKey(viewType);
return position >= ;
} /**
* 创建头部或者底部的ViewHolder
*/
private RecyclerView.ViewHolder createHeaderFooterViewHolder(View view) {
return new RecyclerView.ViewHolder(view) { };
} /**
* 是不是头部类型
*/
private boolean isHeaderViewType(int viewType) {
int position = mHeaderViews.indexOfKey(viewType);
return position >= ;
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (isHeaderPosition(position) || isFooterPosition(position)) {
return;
} // 计算一下位置
final int adapterPosition = position - mHeaderViews.size();
mAdapter.onBindViewHolder(holder, adapterPosition); // 设置点击和长按事件
if (mItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mItemClickListener.onItemClick(v, adapterPosition);
}
});
}
if (mLongClickListener != null) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return mLongClickListener.onLongClick(v, adapterPosition);
}
});
}
} @Override
public int getItemViewType(int position) {
if (isHeaderPosition(position)) {
// 直接返回position位置的key
return mHeaderViews.keyAt(position);
}
if (isFooterPosition(position)) {
// 直接返回position位置的key
position = position - mHeaderViews.size() - mAdapter.getItemCount();
return mFooterViews.keyAt(position);
}
// 返回列表Adapter的getItemViewType
position = position - mHeaderViews.size();
return mAdapter.getItemViewType(position);
} /**
* 是不是底部位置
*/
private boolean isFooterPosition(int position) {
return position >= (mHeaderViews.size() + mAdapter.getItemCount());
} /**
* 是不是头部位置
*/
private boolean isHeaderPosition(int position) {
return position < mHeaderViews.size();
} @Override
public int getItemCount() {
// 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数
return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();
} /**
* 获取列表的Adapter
*/
private RecyclerView.Adapter getAdapter() {
return mAdapter;
} // 添加头部
public void addHeaderView(View view) {
int position = mHeaderViews.indexOfValue(view);
if (position < ) {
mHeaderViews.put(BASE_ITEM_TYPE_HEADER++, view);
}
notifyDataSetChanged();
} // 添加底部
public void addFooterView(View view) {
int position = mFooterViews.indexOfValue(view);
if (position < ) {
mFooterViews.put(BASE_ITEM_TYPE_FOOTER++, view);
}
notifyDataSetChanged();
} // 移除头部
public void removeHeaderView(View view) {
int index = mHeaderViews.indexOfValue(view);
if (index < ) return;
mHeaderViews.removeAt(index);
notifyDataSetChanged();
} // 移除底部
public void removeFooterView(View view) {
int index = mFooterViews.indexOfValue(view);
if (index < ) return;
mFooterViews.removeAt(index);
notifyDataSetChanged();
} /**
* 解决GridLayoutManager添加头部和底部不占用一行的问题
*
* @param recycler
* @version 1.0
*/
public void adjustSpanSize(RecyclerView recycler) {
if (recycler.getLayoutManager() instanceof GridLayoutManager) {
final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
boolean isHeaderOrFooter =
isHeaderPosition(position) || isFooterPosition(position);
return isHeaderOrFooter ? layoutManager.getSpanCount() : ;
}
});
}
} /***************
* 给条目设置点击和长按事件
*********************/
public OnItemClickListener mItemClickListener;
public OnLongClickListener mLongClickListener; public void setOnItemClickListener(OnItemClickListener itemClickListener) {
this.mItemClickListener = itemClickListener;
} public void setOnLongClickListener(OnLongClickListener longClickListener) {
this.mLongClickListener = longClickListener;
}
}

2.构建WrapRecyclerView

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

 /**
* Description: 可以添加头部和底部的RecyclerView
*/
public class WrapRecyclerView extends RecyclerView {
// 包裹了一层的头部底部Adapter
private WrapRecyclerAdapter mWrapRecyclerAdapter;
// 这个是列表数据的Adapter
private Adapter mAdapter; // 增加一些通用功能
// 空列表数据应该显示的空View
// 正在加载数据页面,也就是正在获取后台接口页面
private View mEmptyView, mLoadingView; public WrapRecyclerView(Context context) {
super(context);
} public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
} public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public void setAdapter(Adapter adapter) {
// 为了防止多次设置Adapter
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mDataObserver);
mAdapter = null;
} this.mAdapter = adapter; if (adapter instanceof WrapRecyclerAdapter) {
mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter;
} else {
mWrapRecyclerAdapter = new WrapRecyclerAdapter(adapter);
} super.setAdapter(mWrapRecyclerAdapter); // 注册一个观察者
mAdapter.registerAdapterDataObserver(mDataObserver); // 解决GridLayout添加头部和底部也要占据一行
mWrapRecyclerAdapter.adjustSpanSize(this); // 加载数据页面
if (mLoadingView != null && mLoadingView.getVisibility() == View.VISIBLE) {
mLoadingView.setVisibility(View.GONE);
} if (mItemClickListener != null) {
mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener);
} if (mLongClickListener != null) {
mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener);
}
} // 添加头部
public void addHeaderView(View view) {
// 如果没有Adapter那么就不添加,也可以选择抛异常提示
// 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.addHeaderView(view);
}
} // 添加底部
public void addFooterView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.addFooterView(view);
}
} // 移除头部
public void removeHeaderView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.removeHeaderView(view);
}
} // 移除底部
public void removeFooterView(View view) {
if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.removeFooterView(view);
}
} private AdapterDataObserver mDataObserver = new AdapterDataObserver() {
@Override
public void onChanged() {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyDataSetChanged(); dataChanged();
} @Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyItemRemoved(positionStart);
dataChanged();
} @Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
dataChanged();
} @Override
public void onItemRangeChanged(int positionStart, int itemCount) {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart);
dataChanged();
} @Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyItemChanged(positionStart, payload);
dataChanged();
} @Override
public void onItemRangeInserted(int positionStart, int itemCount) {
if (mAdapter == null) return;
// 观察者 列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果
if (mWrapRecyclerAdapter != mAdapter)
mWrapRecyclerAdapter.notifyItemInserted(positionStart);
dataChanged();
}
}; /**
* 添加一个空列表数据页面
*/
public void addEmptyView(View emptyView) {
this.mEmptyView = emptyView;
} /**
* 添加一个正在加载数据的页面
*/
public void addLoadingView(View loadingView) {
this.mLoadingView = loadingView;
mLoadingView.setVisibility(View.VISIBLE);
} /**
* Adapter数据改变的方法
*/
private void dataChanged() {
if (mAdapter.getItemCount() == ) {
// 没有数据
if (mEmptyView != null) {
mEmptyView.setVisibility(VISIBLE);
}
} else {
// 没有数据
if (mEmptyView != null) {
mEmptyView.setVisibility(GONE);
}
}
} /***************
* 给条目设置点击和长按事件
*********************/
public com.zzw.framelibray.recyclerview.adapter.OnItemClickListener mItemClickListener;
public com.zzw.framelibray.recyclerview.adapter.OnLongClickListener mLongClickListener; public void setOnItemClickListener(com.zzw.framelibray.recyclerview.adapter.OnItemClickListener itemClickListener) {
this.mItemClickListener = itemClickListener; if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.setOnItemClickListener(mItemClickListener);
}
} public void setOnLongClickListener(com.zzw.framelibray.recyclerview.adapter.OnLongClickListener longClickListener) {
this.mLongClickListener = longClickListener; if (mWrapRecyclerAdapter != null) {
mWrapRecyclerAdapter.setOnLongClickListener(mLongClickListener);
}
}
}

3.使用:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> <com.zzw.framelibray.recyclerview.view.WrapRecyclerView
android:id="@+id/wrap_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </LinearLayout>
Activity
 public class HeaderFooterActivity extends AppCompatActivity implements OnItemClickListener {

     private WrapRecyclerView mRecyclerView;
private List<People> mData; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view);
mRecyclerView = (WrapRecyclerView) findViewById(R.id.wrap_recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mData =new ArrayList<>();
mData.add(new People());
mData.add(new People());
mData.add(new People()); PeopleListAdapter listAdapter = new PeopleListAdapter(this, mData); // 添加头部和底部 需要 包裹Adapter,才能添加头部和底部
WrapRecyclerAdapter wrapRecyclerAdapter = new WrapRecyclerAdapter(listAdapter);
mRecyclerView.setAdapter(wrapRecyclerAdapter); wrapRecyclerAdapter.setOnItemClickListener(this); // 添加头部和底部
wrapRecyclerAdapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false));
wrapRecyclerAdapter.addFooterView(LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false));
} @Override
public void onItemClick(View view, int position) {
Toast.makeText(this, "" + mData.get(position).name, Toast.LENGTH_SHORT).show();
} class PeopleListAdapter extends CommonRecyclerAdapter<People> { public PeopleListAdapter(Context context, List<People> datas) {
super(context, datas, R.layout.channel_list_item);
} @Override
public void convert(ViewHolder holder, People item, int position) {
holder.setText(R.id.action_btn, item.name+position);
}
} class People{
String name="王伟:";
}
}

RecyclerView--添加头部和底部的更多相关文章

  1. RecyclerView添加头部和底部视图的实现

    ListView是有addHeaderView和 addFooterView两个方法的. 但是作为官方推荐的ListView的升级版RecyclerView缺无法实现这两个方法. 那么如果使用Recy ...

  2. RecyclerView添加头部和底部视图的实现方法

    引用-- http://www.zhimengzhe.com/Androidkaifa/15072.html 在天下货crm----签到---签到记录中有使用

  3. 可添加头部尾部RecyclerView,很帅哦~

    WrapRecyclerView 是一个可以添加头部和尾部的RecyclerView,并且提供了一个 WrapAdapter, 它可以让你轻松为 RecyclerView 添加头部和尾部.   示例中 ...

  4. Android 5.X新特性之为RecyclerView添加HeaderView和FooterView

    上一节我们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信大家也应该熟悉了RecyclerView的基本使用,这一节我们来学习下,为RecyclerView添加H ...

  5. Android RecyclerView添加Header头部

     Android RecyclerView添加Header头部 Android RecyclerView不像以前的ListView那样直接添加头部,如果要给RecyclerView增加头部,则需要 ...

  6. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  7. RecyclerView添加Header的正确方式

    原文链接:http://blog.csdn.net/qibin0506/article/details/49716795 看了一下博客目录,已经有好几篇博客是关于RecyclerView的,不过对于这 ...

  8. HTML5 开发APP(头部和底部选项卡)

    我们开发app有一定固定的样式,比如头部和底部选项卡部分就是公共部分就比如我在做的app进来的主页面就像图片显示的那样 我们该怎么实现呢,实现我们应该建一个主页面index.html,然后建五个子页面 ...

  9. ionic-CSS:ionic 头部与底部

    ylbtech-ionic-CSS:ionic 头部与底部 1.返回顶部 1. ionic 头部与底部 Header(头部) Header是固定在屏幕顶部的组件,可以包如标题和左右的功能按钮. ion ...

随机推荐

  1. gradle构建工具

    在使用android studio开发android程序时,as就是基于gradle进行构建的,我们只需要通过run就可以编译.打包.安装,非常方便,但是究竟gradle是什么呢?  一.java构建 ...

  2. C#:使用ListView动态添加数据一直闪烁的解决办法

    首先,自定义一个类ListViewNF,继承自 System.Windows.Forms.ListView using System; using System.Collections.Generic ...

  3. 输入两棵二叉树A,B,判断B是不是A的子结构(c++实现)

    #include <iostream> #include <cstdio> #include <stdio.h> #include <string> # ...

  4. Git基本命令学习

    Git是一个由林纳斯·托瓦兹为了更好地管理linux内核开发而创立的分布式版本控制/软件配置管理软件,如今已经超越CVS.SVN称为主流的版本控制器.许多著名的开源项目都用Git管理,比较火的托管服务 ...

  5. Redis for Windows

    要求 必备知识 熟悉基本编程环境搭建. 运行环境 windows 7(64位); redis64-2.8.17 下载地址 环境下载 什么是Redis redis是一个key-value存储系统.和Me ...

  6. 在商城系统中使用设计模式----策略模式之在spring中使用策略模式

    1.前言: 这是策略模式在spring中的使用,对策略模式不了解对同学可以移步在商城中简单对使用策略模式. 2.问题: 在策略模式中,我们创建表示各种策略的对象和一个行为,随着策略对象改变而改变的 c ...

  7. Hadoop不适合处理实时数据的原因剖析

    1.概述 Hadoop已被公认为大数据分析领域无可争辩的王者,它专注与批处理.这种模型对许多情形(比如:为网页建立索引)已经足够,但还存在其他一些使用模型,它们需要来自高度动态的来源的实时信息.为了解 ...

  8. 关于VS2017的安装和WDK的选择问题

    首先就是关于VS2017的安装,我们可以通过微软的官网去寻找我们想要安装的VS版本 我们可以随便选择一个我们需要的版本进行下载,任意版本的VS都可以. 然后下载安装的时候,要进行一下这个安装选项的选择 ...

  9. 【转载】配置文件报错:不允许有匹配 [xX][mM][lL] 的处理指令目标

    今天编写代码的时候,不小心给一个xml文件的首行加了一行空格,导致了启动报了如题类似的错误,查到一篇文章,顺藤摸瓜发现了这个失误,文章转载如下: 框架整合 的时候,XML 配置文件大多数情况是从另一个 ...

  10. 复刻smartbits的国产网络性能测试工具minismb-如何配置Ping报文

    复刻smartbits的国产网络性能测试工具minismb,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此以太网测试工具测试任何ip网络设备的端口吞吐率,带宽, ...