(周期计划-2)RecyclerView封装系列(1):Header、Footer

简介: ​2018年技术周期计划:周期计划-2(2018/1/8-2018/1/14)写在前面写这边文章的时候是2018年1月12日,也就是18年的第二周,按照原计划应该是关于分割线的封装,不过后来想一想既然提到了封装,那不如多写一写,因此有了这个封装系列。

2018年技术周期计划:周期计划-2(2018/1/8-2018/1/14)

写在前面

写这边文章的时候是2018年1月12日,也就是18年的第二周,按照原计划应该是关于分割线的封装,不过后来想一想既然提到了封装,那不如多写一写,因此有了这个封装系列。
这个系列的开篇是关于Header和Footer的封装思路。

感兴趣的看官,可以看看我的其他文章:
1、常用集合的源码分析:HashMap
2、Java反射实践:从反射中理解class
3、从公司项目配置看Gradle

开始

效果在这里就不浪费篇幅去展示了,估计大家也都知道。

正常思路

给RecyclerView增加头部布局本身不存在什么难度,按照我们正常的流程,写一个符合我们业务逻辑的头部布局的ViewHolder,然后在getItemViewType()里通过position返回一个表示头部布局ViewHolder的Type类型,然后在onCreateItemViewHolder(ViewGroup parent, int viewType)里通过viewType来初始化return我们不同的ViewHolder。

这用做法,肯定是没有什么毛病。但是如果我们需要频繁的使用不同的头部布局,那么我们就要考虑去封装这个问题了。这里简单的提供一种封装的思路,(当然这种思路是存在于弊端的,那就是这种封装是基于业务的封装,系列计划中会有关于抽取的封装思路)如果有更好的思路,欢迎讨论。


封装思路(有点水)

这里提供的思路并不具备可移植性,因为是基于业务本身的封装,所以核心是继承RecyclerView.Adapter并拓展。因为这个项目的本身并不单单是封装Header,而是同样包括了下拉、下拉、分割线等操作。主要还是为了梳理并记录这么一种基于业务的思想。

这里封装的思想,直接延续正常的思路,也就是基于Type的对外封装。

首先,让我们的这个类去继承RecyclerView.Adapter,例如这样:HeaderRecyclerViewAdapter extends RecyclerView.Adapter。

然后在构造方法中传入我们正常的Adapter,然后创建俩个List<View>,用于放置我们的Header以及Footer。
对应的我们要对外暴露相应的add方法:

    public void addHeader(View headerView) {
        if (!headerViews.contains(headerView)) {
            headerViews.add(headerView);
            //当然这里可以使用notifyItemChanged(int position)去优化
            notifyDataSetChanged();
        }
    }

给Header设置一个合适的Type,比如:

public static final int VIEW_TYPE_HEADER_OFFSET = Integer.MIN_VALUE;

接下来就是getItemViewType()方法的处理了。

    @Override
    public int getItemViewType(int position) {
        if (!headerViews.isEmpty() && position < headerViews.size()) {
            return VIEW_TYPE_HEADER_OFFSET + position;
        }
        //计算我们常规数据的position,也就是减去Header的List的size的数量即可
        if (!headerViews.isEmpty()) {
            position -= headerViews.size();
        }
        //adapter就是我们在构造方法里传进来的RecyclerView.Adapter
        if (adapter != null && position < adapter.getItemCount()) {
            return adapter.getItemViewType(position);
        }     
    }

return了viewType,那么我们就要处理onCreateViewHolder()方法了。

    public static boolean isHeaderView(int viewType) {
        return viewType < VIEW_TYPE_HEADER_OFFSET;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (isHeaderView(viewType)) {
            return new HeaderViewHolder(headerViews.get(viewType - VIEW_TYPE_HEADER_OFFSET));
        }
        return adapter.onCreateViewHolder(parent, viewType);
    }

紧接着就是处理onBindViewHolder()方法。其实这里对于我们来说并不需要处理,因为我们来说,Header的操作应该交由外部处理,因此这里我们return掉,只需要对常规数据的adapter,调用super方法即可。

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int viewType = getItemViewType(position);
        //这里直接return的原因,我们这里不做对Header的处理,交由外部。
        if (isHeaderView(viewType)) {
            return;
        }
        position -= headerViews.size();
        adapter.onBindViewHolder(holder, position);
    }

到这我们的针对Header的封装就算是结束了,使用的时候也很简单,只需要在初始化了这个实现类后调用addHeader方法,传入我们自己的布局即可。(单纯只看这个封装,其实并不能给我们带来多么大的体验,但是如果综合多个功能去封装那所带来的战斗力将不言而喻)

Footer的话,和Header是同理的。


总结

其实单单是为了封装Header本身的意义并不大,就像上诉的列子,并无法给我们带来多么大的便利,但是如果我们综合去封装,就可以发现它存在的意义,比如:我的观公司RecyclerView封装有感中那样,把对应的功能封装到一起,那么作为一个业务的基类,我们将会发现可以很快捷完成不少类似的业务。

2018年7月2号,我正式开始了自己的Android工作,为了能够让自己能够好好完成工作,并且能够快速得到技术提升。所以打算以公众号的方式去敦促自己学习,我会把自己日常的学习笔记发布到公众号上,如果可以,共同进步!~


img_89788b3a8f3f86257453cbc8264959f6.png
个人公众号
目录
相关文章
|
7月前
Nuxt3 实战 (五):Header 头部布局
这篇文章介绍了作者忙于公司系统迭代需求,但抽空完成了布局的Header部分。文章提到了需求的拆分,布局的组件拆分,并介绍了Nuxt框架以及安装和启用插件的步骤。还提到了白天暗黑模式切换组件和SVG跟随模式的组件的创建。最后,文章提到了PC端和移动端的最终实现效果,并给出了Github仓库和在线预览链接。
124 0
Nuxt3 实战 (五):Header 头部布局
|
存储 缓存 索引
RecyclerView 动画原理 | pre-layout,post-layout 与 scrap 缓存的关系
RecyclerView 动画原理 | pre-layout,post-layout 与 scrap 缓存的关系
89 0
|
Android开发
ViewPager源码分析(2):滑动及冲突处理
我的简书同步发布:ViewPager源码分析(2):滑动及冲突处理 转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】 上一篇介绍了ViewPager的onMeasure和onLayout两个方法,这是自定义View最基本的两个函数。但是我们的ViewPager有个需求就是滑动,接下来我们一起去学习ViewPager在滑动方面做了哪些工作,以及ViewPager如何处理与子View之间的滑动冲突。由于ViewPager的子View有Decor View还有普通的子View,而本篇文章讲的主要是普通子View,因此,不再去刻意区
ViewPager源码分析(2):滑动及冲突处理
ViewPager2实现内部Item的动态滚动
最近接到了一个需求,大概类似如下图所示的一个样式(省略了部分细节,不影响大概)。
349 0
html+css实战180-header-布局
html+css实战180-header-布局
129 0
html+css实战180-header-布局
|
API Android开发
实现一个带有header和footer功能的RecyclerView
这是我之前一篇老文章了,重新整理了一下在掘金发一下,大家可以参考参考。 RecyclerView是Android 5.0版本引入的一个新的组件,目的是在一些场景中取代之前ListView和GridView,实现性能更优的解决方案。同时RecyclerView的灵活性让它可胜任更多的场景。关于RecyclerView的使用有太多的文章了,大家可以自行搜索。 我们知道RecyclerView很灵活,灵活到很多功能需要我们自己实现,比如ListView和GridView中最常用的Item点击事件。所以在使用了几次后,我准备自己封装一个WrapRecyclerView,实现一些非常常用的功能。
254 0
html+css实战131-header布局
html+css实战131-header布局
239 0
自定义tableView的section header/footerView时的view复用问题
自定义tableView的section header/footerView时的view复用问题
367 0
|
缓存
RecyclerView局部刷新机制——payload
这篇文章其实之前就完成了,一直遗忘在角落里了,今天无意翻之前的笔记发现的,大部分内容应该还是有效的。 之前在使用RecyclerView的遇到过一个问题,使用notifyItemChanged刷新数据的时候会出现重影或者闪烁的现象。 这个问题很容易出现,当我们的列表中有进度显示(比如下载),这时候需要不停的更新进度,就需要使用notifyItemChanged 使用notifyItemChanged可以只刷新那一个item,这样就避免了像ListView那样全部刷新 但是如果使用notifyItemChanged(position),在滑动的时候刷新就会出现重影或者闪烁的问题。
600 0
|
消息中间件 XML 存储
面试官:View.post() 为什么能够获取到 View 的宽高 ?
面试官:View.post() 为什么能够获取到 View 的宽高 ?