对于RecyclerView, 我们重复编写着那一个又一个的列表界面,有的要分组,有的要添加广告头部、有的要不同类型item排列、等等需求,主要代码有大部分是重复的,如果有一个框架能够帮快速的解决各种需求,那该多好。
BRVAH是GitHub上一个强大的RecyclerAdapter框架,它能节约开发者大量的开发时间,它集成了大部分列表常用需求解决方案。 该框架于2016年4月10号发布,至今,经历了700多次迭代。
presentation by吴思博
github:https://github.com/CymChad/BaseRecyclerViewAdapterHelper
official website:www.recyclerview.org
Author(Brvah) blog:http://www.jianshu.com/u/f958e66439f0
它能干吗?
解放你的双手,让你少码代码!
列表、子布局
一行代码轻松切换5种动画
让你感觉又回到ListView时代!
哼、列表需求来呀!
它带来了什么好处?
提高效率
BRVAH是Github上的一个很棒的开源项目,主要作用是帮助我们更加高效的使用Recyclerview控件,处理项目中常见需求的Adapter,使用起来非常方便。
BRVAH主要是针对Adapter来设计的,为我们提供了一般情况下的BaseQuickAdapter,和几个特定需求下的Adapter,BaseMultiItemQuickAdapter用于复杂类布局列表;BaseItemDraggableAdapter用于拖拽移动和滑动删除类列表;BaseSectionQuickAdapter用于带Section头部View的列表。
一、框架引入:
二、基本使用
Activity代码:(和普通的一样)
正常的adapter写法:
onCreateViewHolder(这个方法主要生成为每个Item inflater出一个View,方法返回的是一个ViewHolder。 方法是把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,这个ViewHolder需要我们自己去编写。直接省去了当初Listview的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。)和onBindViewHolder(这个方法主要用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView)等方法。
使用BRAVH的Adapter:
首先需要继承BaseQuickAdapter,然后BaseQuickAdapter中第一个泛型T是数据实体类型,第二个BaseViewHolder是ViewHolder,其目的是为了支持扩展ViewHolder。
可以通过viewHolder.getView(viewId)获取该控件。 通过viewHolder.getLayoutPosition()获取当前item的position。(为什么有数据不显示?检查一下的RecyclerView是否设置了LayoutManager。)
代码量是3:1的比例!
和原始的adapter相对,减少了70%的代码量。
实现思路:
找到重复部分代码,抽取到基类,非重复部分用抽象方法代替,具体让子类实现。具体代码BaseQuickAdapter如下:(onCreateViewHolder方法和普通adapter一样,对onBindViewHolder方法进行了提取,使用抽象方法convert(抽象方法)代替。)
接下来再看看BaseViewHolder怎么写的:( 把ViewHolder进行了封装,利用了SparseArray,加快了查找已创建好控件的速度,没有创建再使用findviewbyId再存入SparseArray)
三、强大的功能
1.复杂布局实现(多布局)
在实际应用中经常会遇到各种样式的列表、宫格和列表同时存在、分类列表等情况。
在云阅读中的使用:“评论页面”(优点: 代码量少,节省时间,简洁,清晰,易维护)
普通多布局写法:
getItemViewType方法,根据位置获取当前item的类型,在onCreateViewHolder和onBindViewHolder中匹配类型进行操作。
BRAVH是怎么实现?
1、实体类(UserComment)实现MultiItemEntity接口,在设置数据的时候,给每一个数据设置itemType。
评论的实体类:
2、adapter继承BaseMultiItemQuickAdapter类,在构造方法中调用addItemType()方法加入定义的itemType和对应布局, 在Activity中实例化即可。
和原始的adapter相对,减少70%的代码量,更加清晰易于维护。
原理分析:
1.2宫格和列表的混排样式
关于Grid和List的混排样式,Grid样式是一行有多个,而List样式是一行只有一个。 我们可以把List样式看成是Grid样式,它就相当于把一个Grid的item拉长了的样子。
列表与网格混排的布局效果,我们可以创建adapter继承BaseMultiItemQuickAdapter添加对应item类型的布局文件,也可以在Activity中创建GridLayoutManager对象,设置spanSize属性,通过Adapter的setSpanSizeLookup()方法设置每种item类型对应的spanSize。设置Recyclerview的addItemDecoration()方法设置添加分割线或设置item间距。
在创建GridLayoutManager对象时,spanSize的参数需要设置,它的作用就是使原来一个item占满一行变为可以最多三个item占满一行。
而设置setSpanSizeLookup()方法返回的是对应每种item类型返回具体的横跨大小。比如代码中TYPE_GRID类型的item在设置的spanSize是1,而GridLayoutManager设置的spanSize是3,那么该类型的item就会以3个item占满一行,相当于每个item占一行的1/3。
代码片段:
在我们使用addItemDecoration()添加分割线的方法中对这种混排的列表设置item间距的时候,在getItemOffsets()方法里,通过GridLayoutManager.LayoutParams获取spanSize来确定item类型设置对应间距, 其中spanIndex表示当前行item对应的下标位置,从左到右依次从0开始。
1.3 Recyclerview嵌套Recyclerview的复杂布局
我们“文学漫画”产品中,那些地方用到这种布局?例如蜗牛的领读ReadTrendFragment、Lofter发现音乐Fragment、 云阅读书店BookStoreFragment。
蜗牛的领读ReadTrendFragmentLofter发现的音乐Fragment
这种界面布局样式,最外面一个RecyclerView,它里面嵌套一个RecyclerView。继承BaseMultiItemQuickAdapter在重写的convert()方法中实例化子Recyclerview。
需要注意的是Recyclerview嵌套Recyclerview会出现子Recyclerview抢焦点的问题, 导致界面顶部部分控件被挤出, 只需在最外面的Recyclerview的包裹容器中设置属性
Android:descendantFocusability="blocksDescendants"即可。
2.实现了点击监听事件
BRVAH为我们提供好了全面的item和item子View的监听事件,我们只需在继承它提供的Adapter的基础上,通过adapter来调用对应的监听。 设置监听子View前,我们需要在adapter中对应的item的子View注册对应的监听事件。
直接在Activity中添加item点击事件,和listview一样。
item长按监听事件
首先需要在adapter中,注册子View的监听事件。
2.3也可以通过viewHolder.getView(viewId)获取该控件,再设置监听。
3实现列表加载动画效果
3.1默认动画
我们只需将自建的adapter继承它对应满足需求的Adapter,然后在Activity中实例化,通过openLoadAnimation()方法完成特定的动画效果。
BRVAH支持5种动画:
渐显、缩放、从下到上,从左到右、从右到左
3.2自定义动画
我们也可以自定义动画,通过实现BaseAnimation这个类,重写
getAnimators(View view)方法来完成自定义动画。
3.3动画其他设置
动画默认只执行一次,如果想重复执行可设置: mQuickAdapter.isFirstOnly(false);
设置不显示动画数量:adapter.setNotDoAnimationCount(count);
由于进入界面的item都是很多的速度进来的所以不会出现滑动显示的依次执行动画效果,这个时候会一起执行动画,如果觉得这样的效果不好可以使用setNotDoAnimationCount设置第一屏item不执行动画, 但是如果需要依次执行动画可以重写startAnim让第一个屏幕的item动画延迟执行即可。
如何做到的?
首先判断是否开启动画,然后判断是否是自定义动画还是用户选择的自带动画,然后对动画的操作元素进行遍历执行,执行时间为300毫秒,由于上面说了每次填充数据都会调用,所以如何不判断的话,就会导致上下滑动每次都会重复调用动画,动画本身是会耗费性能的。添加一个mLastPosition来存储滑动过的位置,然后判断滑动的位置是否被滑动过,这样就可以避免每次都添加动画了。不过为了满足喜欢动画多过于性能的开发者,如果你想要每次滑动都带动画可以设置isFirstOnly属性即可,默认是不开启的。
4添加头部、尾部只需要一行代码。
添加:
删除指定view:
删除所有:
默认出现了头部就不会显示Empty,和尾部,配置以下方法也支持同时显示:
默认头部尾部都是占满一行,如果需要不占满可以配置:
其中HeaderView和FooterView可以包含多个View,LoadingMoreView在BRVAH中固定成了一个。无论HeaderView里面包含了多少个Header,HeaderView会被整体当成一个Item,所以当Adapter需要刷新HeaderView的时候始终都是刷新position = 0的位置(同理,FooterView也是一个道理)
这里需要重点理解的是HeaderView中Header的数量和RecycleView整个Item数量之间的关系,BRVAH中,HeaderView和FooterView都是LinerLayout,向这个LinerLayout中增加View是不影响RecycleView的ItemCount的。千万不要想当然的认为Add了几个Header然后ItemCount就会加几了。这点理解了源代码理解起来就很容易了
5.实现Recyclerview刷新
这个框架也帮我们实现了,下拉刷新,上拉加载等,傻瓜式实现。
5.1上拉加载
在按照BRVAH框架设置完adapter后,在Activity中让类实现BaseQuickAdapter.RequestLoadMoreListener接口,重写onLoadMoreRequested( )方法,在方法中调用mAdapter.addData()来添加新的数据,接着设置mAdapter.loadMoreComplete(),在数据都加载完后设置mAdapter.loadMoreEnd(false)显示数据加载完毕。
默认第一次加载会进入回调,如果不需要可以配置:
mQuickAdapter.disableLoadMoreIfNotFullPage();
5.2设置自定义加载布局
mQuickAdapter.setLoadMoreView(newCustomLoadMoreView());
(注意:如果上拉结束后,下拉刷新需要再次开启上拉监听,需要使用setNewData方法填充数据。)
5.3下拉刷新
6.实现分组布局
设置MySection类继承SectionEntity,创建不同的构造方法来设置item是否有header。 在adapter中,增加了convertHead()方法来加载head数据。在Activity中根据数据创建不同的MySection对象加入集合,设置给adapter。
根据数据确定不同的样式,用不同的构造方法设置item布局。
在adapter中,构造方法需要传入两个不同的布局id,第一个是item的layout id,第二个是head,item的数据加载在convert()方法中,head的数据加载在convertHead()方法中。
7.设置空布局
一行代码搞定。
//没有数据的时候默认显示该布局
mQuickAdapter.setEmptyView(getView());
8.实现Recyclerview拖拽滑动删除
添加RecyclerView的拖拽和滑动移除很简单,只需adapter继承BaseItemDraggableAdapter类,在Activity中,添加OnItemDragListener和OnItemSwipeListener两个接口,通过adapter配置基本属性即可。
Activity使用代码:
拖拽和滑动删除的回调方法
adapter需要继承BaseItemDraggableAdapter
默认不支持多个不同的ViewType之间进行拖拽,如果开发者有所需求:
9自定义ViewHolder
需要继承BaseViewHolder
publicclassMovieViewHolderextendsBaseViewHolder
然后修改adapter的第二个泛型为自定义的ViewHolder
publicclassDataBindingUseAdapterextendsBaseQuickAdapter
注意:需要单独建一个外部类继承BaseViewHolder,否则部分机型会出现ClassCastException,如果是内部类的构造方法要是public,定义的那个类也最好是public。
10添加data方法
11其它
树形列表,查看官方网站
四、总结
找到重复部分代码,抽取到基类,非重复部分用抽象方法代替,具体让子类实现。提高了代码复用率, 减少了代码量, 轻松添加各种点击事件,多布局, 一行代码添加加载动画效果,添加头部、尾部、下拉刷新、上拉加载、让你感觉又回到ListView时代! 最重要的是在我们“文学漫画”产品中也可以很好的接入。
Thank you!!
网友评论