上一节我们讲到了 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. Ubuntu下利用Mono,Jexus搭建Asp.Net(MVC) Web服务器

    最近在Ubuntu上搭建了Asp.Net的Web服务器,其中遇到很多问题,整理一下思路,以备后用. 搭建环境以及配套软件 Ubuntu: 11.10 Mono:3.0.6 下载地址(http://do ...

  2. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  3. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  4. python获取ip代理列表爬虫

    最近练习写爬虫,本来爬几张mm图做测试,可是爬到几十张的时候就会返回403错误,这是被网站服务器发现了,把我给屏蔽了. 因此需要使用代理IP.为了方便以后使用,我打算先写一个自动爬取ip代理的爬虫,正 ...

  5. Failed to stop iptables.service: Unit iptables.service not loaded.

    redhat 7 [root@lk0 ~]# service iptables stop Redirecting to /bin/systemctl stop iptables.service Fai ...

  6. node.js学习总结(一)

    1.1.1 安装 Node.js 有三种方式安装 Node.js:一是通过安装包安装,二是通过源码编译安装,三是在 Linux 下可以通过 yum|apt-get 安装,在 Mac 下可以通过 Hom ...

  7. HTML5_04之SVG绘图

    1.关于Canvas绘制图像: 问题:需要绘制多张图片时,必须等待所有图片加载完成才能开始绘制:而每张图片都是异步请求,彼此没有先后顺序,哪一张先加载完成完全无法预测: 方案: var progres ...

  8. ERP软件的价格设计

    ERP体现出信息流.资金流.物流在供应商.企业.客户间的运营方向,是以销售为源头,生产.物料需求计划为核心,以金额.实时数据为基础的整体.ERP的核心是MRP(物料需求).企业的经营活动最终是为了赢利 ...

  9. div中设置滚动条的问题

    <div srtle="width:100px;height:50px;"></div> 这样的一个div,当文本超出的时候我们就会设: overflow: ...

  10. MVC5 网站开发之六 管理员 2、添加、删除、重置密码、修改密码、列表浏览

    目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 MVC5 网站开发之三 数据存储层功能实现 MVC5 网站开发之四 业务逻辑层的架构和基本功能 MVC5 网 ...