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

针对RecyclerView的头部和底部,官方并没有给我们提供像listView一样可以直接通过addHeaderView()/addFooterView()的方法,所以只能靠我们自己去实现了,那怎么实现呢?大家都知道RecyclerView已经为我们封装好了Adapter和ViewHolder,在Adapter中我们需要重写onCreateViewHolder(ViewGroup parent, int viewType)这个方法方便我们把ItemView布局文件或是自定义View传递到ViewHolder中,从而达到ItemView的重复使用和回收等。而我们今天要讲的添加头部和底部和该方法有密不可分的关系。

大家仔细观察onCreateViewHolder(ViewGroup parent, int viewType)这个方法,在它的参数中,含有一个viewType,它就代表了每一个子列表中的ItemView的类型,而该类型我们又可以通过Adapter中封装好的getItemViewType()方法来定义。因此,我们可以根据这两个方法来完成我们今天的学习。

首先,我们也需要在BaseRecyclerAdapter中添加一个addHeaderView的方法,用于接受Activity中传递过来的HeaderView,并且把HeaderView添加到第0个ItemView中。

	private View mHeaderView;
public void addHeaderView(View headerView){
mHeaderView = headerView;
notifyItemInserted(0);
}

然后,我们在我们自定义的BaseRecyclerAdapter中重写getItemViewType()方法,并且定义两个静态变量来区分我们的viewType的类型,如下:

	public final static int TYPE_HEADER = 0;
public final static int TYPE_BODY = 1;
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}

ok,现在我们可以针对getItemViewType()方法来为我们的ItemView设置viewType类型了。我们知道,getItemViewType()默认返回的是0这个类型,所以我们重载该方法,在没有mHeaderView时,我们让它返回TYPE_BODY这个类型,而当有mHeaderView,由于把它添加到第0个ItemView中了,所以我们可以根据position等于0的时候让它返回TYPE_HEADER这个类型。定义好的类型将会在onCreateViewHolder()中使用到。

所以我们的getItemViewType方法可以这样设计:

	@Override
public int getItemViewType(int position) {
if(mHeaderView == null)
return TYPE_BODY;
if(position == 0) {
return TYPE_HEADER;
}
return TYPE_BODY;
}

到这里大家已经很明确的知道了每个ItemView的viewType类型了,那么我们就可以在onCreateViewHolder()方法中根据ItemView的viewType来做出不同的判断了,如下:

	@Override
public BaseViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == TYPE_HEADER && mHeaderView != null){
return new BaseViewHolderHelper(mHeaderView);
}
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new BaseViewHolderHelper(view);
}

代码一目了然,就是根据viewType判断是否为TYPE_HEADER,如果是,则添加不同的布局或View,否则,加载正常的布局,其他的不变。

然后,我们就可以在onBindViewHolder(BaseViewHolderHelper holder, int position)方法中根据当前的position位置来绑定我们要显示数据了。

	@Override
public void onBindViewHolder(BaseViewHolderHelper holder, int position) {
if(getItemViewType(position) == TYPE_HEADER){
return;
}else{
if(mHeaderView != null){
position-- ;
}
holder.itemView.setTag(position);
holder.itemView.setOnClickListener(this);
holder.itemView.setOnLongClickListener(this);
T itemData = mDatas.get(position);
displayContents(holder,itemData);
}
}

代码解释:如果当前position位置的类型是TYPE_HEADER,也就是说用来显示mHeaderView的,这里我们就直接返回mHeaderView的布局,不做事件处理了;如果不是,并且RecyclerView是有带mHeaderView头部的,那么由于它占去第0个itemView,所以我们的position是从第一个开始计算的,所以我们必须得到当前真实position位置,并通过position位置来获取当前的真实数据,如果不带mHeaderView头部,则可直接根据position获取显示数据,其他的逻辑不变。

还有注意的是当mHeaderView不为空时,我们的数据量大小也有一定的变化,请看:

	@Override
public int getItemCount() {
return mHeaderView != null ? mDatas.size() + 1 : mDatas.size();
}

ok,在RecycerActivity的onCreate方法中添加一下两句:

View headerView = LayoutInflater.from(this).inflate(R.layout.item_view1, null);
mBaseRecyclerAdapter.addHeaderView(headerView);

来看看运行结果吧

ok,已经完成了mHeaderView 的添加。但是有个小问题,当你把RecyclerView的布局设置为GridLayoutManager时,如:mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));就会出现这种情况:

这种情况也很好解决,在GridLayoutManager中我们可以在SpanSizeLookup中重新设置显示的列数。

  @Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof GridLayoutManager){
final GridLayoutManager gridLayoutManager = ((GridLayoutManager) manager);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
//是HeaderView则占所有列,否则只占自己列
return getItemViewType(position) == TYPE_HEADER ? gridLayoutManager.getSpanCount() : 1;
}
});
}
}

最主要的就是在getSpanSize方法中根据我们的需要重新设置就ok了。看看吧

好了,mHeaderView 已基本搞定,现在来看看怎么添加FooterView了,其实原理是一样的,也是根据getItemViewType()返回的ViewType类型来加载不同的布局了。

首先我们需要定义一个内部类FooterViewHolder继承我们的BaseViewHolderHelper,它主要是用来绑定FooterView布局文件:

	private class FooterViewHolder extends BaseViewHolderHelper{
private TextView footView;
public FooterViewHolder(View itemView) {
super(itemView);
footView = (TextView) itemView.findViewById(R.id.tv_addFooter);
}
}

然后在getItemViewType中获取到最后的ItemView的位置并返回TYPE_FOOTER类型:

 @Override
private View mFooterView;
public final static int TYPE_FOOTER = 2;
...... public int getItemViewType(int position) {
if(position + 1 == getItemCount()){
return TYPE_FOOTER;
}
if(mHeaderView == null)
return TYPE_BODY;
if(position == 0) {
return TYPE_HEADER;
}
return TYPE_BODY;
}

另外在getItemCount()方法中我们因为添加个一个FooterView所以需要在原来的基础上再加 1 ;

	@Override
public int getItemCount() {
return mHeaderView != null ? mDatas.size() + 2 : mDatas.size() + 1;
}

再次在onCreateViewHolder方法中根据类型加载不同的布局文件:

@Override
public BaseViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
... if(viewType == TYPE_FOOTER){
mFooterView = LayoutInflater.from(mContext).inflate(R.layout.custom_footerview, parent,false);
return new FooterViewHolder(mFooterView);
}
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new BaseViewHolderHelper(view);
}

最后在onBindViewHolder方法中来展示我们的数据吧

	@Override
public void onBindViewHolder(BaseViewHolderHelper holder, int position) {
if(getItemViewType(position) == TYPE_HEADER){
return;
}else if(getItemViewType(position) == TYPE_FOOTER){
FooterViewHolder footViewHolder=(FooterViewHolder)holder;
footViewHolder.footView.setText("上拉加载更多...");
} else{
...
}
}

ok,完成,来看看结果吧

总结下,在给RecyclerView添加HeaderView和FooterView时,只要利用好getItemViewType这个方法,返回相对应的ViewType,并且在onCreateViewHolder方法中根据ViewType类型加载不同的布局就完全可是实现我们的需求了。说起来就是这么简单。好了,今天就讲到这里吧,祝大家学习愉快。

更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。

Android 5.X新特性之为RecyclerView添加HeaderView和FooterView的更多相关文章

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

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

  2. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  3. Android 6.0 新特性 整理 资料来自网络

    Android 6.0新特性 Runtime Permissions Doze and App Standby Apache HTTP Client Removal BoringSSL Access ...

  4. 腾讯云安全:开发者必看|Android 8.0 新特性及开发指南

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 A ...

  5. Android 8.0 新特性

    Android 8.0 (Android Oreo(奥利奥))新特性介绍 通知渠道 - Notification Channels 通知渠道是由应用自行定义的通知内容类别,借助渠道,开发者可以让用户对 ...

  6. 开发者必看|Android 8.0 新特性及开发指南

    背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 Android 系统,今年为 Android 8.0.谷歌在今年3 月21日发布 Andro ...

  7. android 7.0 新特性 和对开发者的影响

    android 7.0新特性 - jiabailong的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/jiabailong/article/details/5241 ...

  8. Atitit.android  jsbridge v1新特性

    Atitit.android  jsbridge v1新特性 1. Java代码调用js并传参其实是通过WebView的loadUrl方法去调用的.只是参数url的写法不一样而已1 2. 三.JAVA ...

  9. Android 5.0 新特性

    Material Design Material Design简介 Material Design是谷歌新的设计语言,谷歌希望寄由此来统一各种平台上的用户体验,Material Design的特点是干 ...

随机推荐

  1. .Net Core 系列:1、环境搭建

    前言: 2016年6月28日微软宣布发布 .NET Core 1.0.ASP.NET Core 1.0 和 Entity Framework Core 1.0. .NET Core是微软在两年前发起的 ...

  2. AutoMapper(四)

    返回总目录 自定义值解析 虽然AutoMapper覆盖了相当一部分目标成员的映射场景,但是还有 1-5%的目标值需要解析处理一下.很多时候,自定义的值解析是可以放在领域层的领域逻辑.然而,如果该逻辑只 ...

  3. 提高代码质量系列之二:重构小技巧——if篇

    前言: if,相信是童鞋们使用的最频繁的关键字了,而且很多时候,我们使用的if都是在无意识的状态下随手而为.键入if,两下回车(我使用了resharper,可以自动编排if的格式),再信手写下我们需要 ...

  4. Android Starting Window(Preview Window)

    当打开一个Activity时,如果这个Activity所属的应用还没有在运行,系统会为这个Activity所属的应用创建一个进程,但进程的创建与初始化都需要时间,在这个动作完成之前系统要做什么呢?如果 ...

  5. 学会使用Spring注解

      概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 ...

  6. Atitit opencv版本新特性attilax总结

    Atitit opencv版本新特性attilax总结 1.1. :OpenCV 3.0 发布,史上功能最全,速度最快的版1 1.2. 应用领域2 1.3. OPENCV2.4.3改进 2.4.2就有 ...

  7. jQuery UI与jQuery easyUI的冲突解决办法

    jQuery UI与jQuery easyUI都是基于jQuery开发的.难免里面会有些方法名冲突! 因此对jQuery.easyui其中的两个方法名:resizable 和 draggable进行替 ...

  8. Chrome在302重定向的时候对原请求产生2次请求的问题说明

    这个问题应该确确实实是一个Chrome的BUG,我在自己的编程环境中发现,并在多个服务器,多个编程语言的运行环境,以及多个浏览器下都测试过,都看到有2次请求出现.为了证明不是自己环境的问题,我也特意去 ...

  9. 【NLP】Tika 文本预处理:抽取各种格式文件内容

    Tika常见格式文件抽取内容并做预处理 作者 白宁超 2016年3月30日18:57:08 摘要:本文主要针对自然语言处理(NLP)过程中,重要基础部分抽取文本内容的预处理.首先我们要意识到预处理的重 ...

  10. markdown常用语法总结

    转自markdown示例[模板] 1.1.段落标题 根据原文中的文档标题可以对应设置标题. # 一级标题## 二级标题### 三级标题 效果 => 一级标题 二级标题 三级标题 1.2.斜体.加 ...