RecyclerView--添加头部和底部
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--添加头部和底部的更多相关文章
- RecyclerView添加头部和底部视图的实现
ListView是有addHeaderView和 addFooterView两个方法的. 但是作为官方推荐的ListView的升级版RecyclerView缺无法实现这两个方法. 那么如果使用Recy ...
- RecyclerView添加头部和底部视图的实现方法
引用-- http://www.zhimengzhe.com/Androidkaifa/15072.html 在天下货crm----签到---签到记录中有使用
- 可添加头部尾部RecyclerView,很帅哦~
WrapRecyclerView 是一个可以添加头部和尾部的RecyclerView,并且提供了一个 WrapAdapter, 它可以让你轻松为 RecyclerView 添加头部和尾部. 示例中 ...
- Android 5.X新特性之为RecyclerView添加HeaderView和FooterView
上一节我们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信大家也应该熟悉了RecyclerView的基本使用,这一节我们来学习下,为RecyclerView添加H ...
- Android RecyclerView添加Header头部
Android RecyclerView添加Header头部 Android RecyclerView不像以前的ListView那样直接添加头部,如果要给RecyclerView增加头部,则需要 ...
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...
- RecyclerView添加Header的正确方式
原文链接:http://blog.csdn.net/qibin0506/article/details/49716795 看了一下博客目录,已经有好几篇博客是关于RecyclerView的,不过对于这 ...
- HTML5 开发APP(头部和底部选项卡)
我们开发app有一定固定的样式,比如头部和底部选项卡部分就是公共部分就比如我在做的app进来的主页面就像图片显示的那样 我们该怎么实现呢,实现我们应该建一个主页面index.html,然后建五个子页面 ...
- ionic-CSS:ionic 头部与底部
ylbtech-ionic-CSS:ionic 头部与底部 1.返回顶部 1. ionic 头部与底部 Header(头部) Header是固定在屏幕顶部的组件,可以包如标题和左右的功能按钮. ion ...
随机推荐
- nc命令简介
nc介绍 ncat/nc 既是一个端口扫描工具,也是一款安全工具,还能是一款监测工具,甚至可以做为一个简单的 TCP 代理. 在大多数 Debian 发行版中,nc 是默认可用的,它会在安装系统的过程 ...
- 用SpringSecurity从零搭建pc项目-02
参照这一篇文章吧,比如你不需要做的那么通用,取其中一部分代码即可. https://www.cnblogs.com/lihaoyang/p/8491792.html
- Jmeter之分布式执行测试
一. 安装Java 1.1下载JDK 1) Windows安装jdk,下载完成后,双击安装 2) Linux解压:tar -zxvf jdk-8u74-linux-x64.gz 1.2 Java环境变 ...
- JDK并发包总结
本文主要介绍jdk中常用的同步控制工具以及并发容器, 其结构如下: 同步控制工具类 ReentrantLock 简而言之, 就是自由度更高的synchronized, 主要具备以下优点. 可重入: 单 ...
- 为什么要设置Java环境变量(windows)
在学习JAVA的过程中,涉及到多个环境变量(environment variable)的概念,如PATH.正确地配置这些环境变量,是能够顺利学习.开发的前提.而经常出现的问题是:有的学习者能够按照提示 ...
- 世界上最短的bash脚本
世界上最短的bash脚本长这样: #!/bin/bash 为啥呢?见下图: 推荐一篇文章,讲解为啥shell脚本开头总是"#!/bin/bash".文风太清奇,不好翻译,看原文吧: ...
- List集合中的对象按照某个字段去重实现
package com.liying.banana.user; import java.util.ArrayList; import java.util.Comparator; import java ...
- drools 的一个小demo
直接上代码: 第一步,maven引入相关包 <?xml version="1.0" encoding="UTF-8"?> <project x ...
- 核心组件之SecurityContextHolder
作用:保留系统当前的安全上下文细节,其中就包括当前使用系统的用户的信息. 上下文细节怎么表示? 用SecurityContext对象来表示 每个用户都会有它的上下文,那这个Securi ...
- Java 使用pipeline对redis进行批量读写
code import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; import java.util.List; p ...