上一节我们讲到了 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. mono -图片处理

    这篇文章中您将了解到以下内容 保存Bitmap WebClient文件上传 向服务端传递数据 保存Bitmap 做移动端开发,图片上传下载是最普通的需求了. 在mono for android中按照资 ...

  2. iOS开发系列--Swift 3.0

    概述 从写第一篇Swift文章的时候到现在Swift已经从1.2发展到了今天的3.0,这期间由于Swift目前还在发展阶段并不能向下兼容,因此第一篇文章中的部分代码在当前的Xcode环境中已经无法运行 ...

  3. iOS开发系列--地图与定位

    概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用和导航应用所特有的.的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式.例如你到了一个 ...

  4. 写自己的Socket框架(三)

    在通信写完了以后,应用层接收到Socket抛上来的byte[],这个时候对于实际的写逻辑的开发者来说,这样的数据并不友好,我们就需要在应用层统一一个包的规则(应用层协议),处理完以后,然后再传给实际的 ...

  5. 小谈Scrum敏捷开发流程

    一晃眼,有两年没有写博客了,回顾前两年,各种奔波,各种忙碌,也有不少的收获.从今天开始,我要把这些收获都分享在这里. 其实这两年,对我影响最大的是开发流程.总所周知,一个好的开发流程,对于项目的进行, ...

  6. [C#版本]有趣啊!各种编程语言实现 2 + 2 = 5

    首页新闻里面那个 [新闻头条]有趣啊!各种编程语言实现 2 + 2 = 5 其他的就不评论的,但是其中C#版的 真是逗比啊...评论中各种吐槽有木有... static void Main (stri ...

  7. AngularJs之四(作用域)

    一:angulaJs的作用域scope Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带.scope 是一个 JavaScript 对象,带有属性和方 ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(28)-系统小结

    系列目录 我们从第一节搭建框架开始直到二十七节,权限管理已经告一段落,相信很多有跟上来的园友,已经搭配完成了,并能从模块创建授权分配和开发功能了 我没有发布所有源代码,但在14节发布了最后的一次源代码 ...

  9. Node.js简单操作

    在node中是不支持BOM和DOM操作的,所以像alert().document.write...都是不支持的,可以是console.log() 首先我们来输出"hello world&qu ...

  10. 读书笔记--SQL必知必会14--组合查询

    14.1 组合查询 复合查询(compound query)或并(union),SQL允许执行多个查询(多条SELECT语句),并将结果作为一个查询结果集返回. 应用场景: 在一个查询中从不同的表返回 ...