一、前言
自从我开始做安卓开发以来,我就得了一种病,Adapter编写焦虑症。在现如今的安卓App开发中,大家用得最多的ViewGroup,那一定是身为老大哥的RecyclerView,单布局列表,多布局列表,网格列表,瀑布流列表,折叠列表,吸顶列表,甚至一个无需滚动的页面,出于屏幕高度适配考虑,都有可能做成列表形式。这足以证明RecyclerView在实际开发中的重要性。
那么这样一个如此重要的组件,通常情况下我们需要怎么实现呢?
第一步:在布局中添加RecyclerVIew
第二步:创建item布局及其实体类
第三步:继承RecyclerView.Adapter类,编写自定义Adapter
第四步:绑定Adapter到RecyclerView
以上便是实现一个完整的列表所需的步骤,其中第三步可谓是整个流程中最为复杂的,目前的一些三方库,在一定程度上简化了第三步,让开发者在继承了他们自定义的Adapter之后,可以少些很大一部分的代码,从而提升开发效率,我以前也是用过这些优秀的库,比如安卓界使用最广泛BRVAH,为开发者们大大减少了开发时间,让大家有时间回家陪陪家人,首先在这里感谢各位大佬的贡献。
但是,由于我接触kotlin比较早,2016年7月开始从事Android开发,2017年初开始接触kotlin,然后在17年5月google开始正式钦定kotlin之后便开始正式使用kotlin做项目,从那时起,我就被kotlin的dsl所吸引,便开始尝试将这些优秀的第三方库进行dsl的改造,奈何当时的能力不足,这种几乎重写的改造宣告失败。既然大型改造不行,那我能不能去找一些别人写好的adapter dsl呢?于是经过我的不断搜索,终于在github上找到了一些库,比如kotlin-adapter和Yasha。
这两个都是优秀的库,曾经我也在项目中使用过他们,但是渐渐地我发现他们已经无法满足我的一些需求了,我便开始尝试写一个自己用的库。当时这个库还是存在于我的私有项目中,我在项目中遇到的问题就可以及时改,直到19年的上半年为止,这个库基本可以用于大多数日常开发,当时我就考虑将它进行一些完善工作后开源,但是世事难料,由于工作原因,19年的7月,我去了一趟柬埔寨,没错,就是程序员们口诛笔伐的东南亚国家之一。
去那边之后,因为人手问题,我不得不学习了vue开发,flutter开发,以及后端开发,几乎没有时间来搞这个库的开源工作。时间到了20年的9月,由于工作安排,又回到了重庆,又经过几个月的忙碌后,终于在最近抽出了一些时间,来继续进行作业。
当我重新审视这个库的时候,我发现了很多可以优化的点,这代表我这一年多是在进步,我很高兴,然后花了两三周的空余时间将其优化完善,新增一些功能后,我决定在今天将它发布出来,希望大家能够喜欢。
不好意思,前言有点啰嗦,但依旧不妨碍后续的精彩。
二、正片
简单介绍一下这个库:YasuoRecyclerViewAdapter ,为什么要取名为Yasuo,因为亚索==快乐!这个库就是为了让大家在写代码的时候感受到快乐而存在的!
1、功能特色
①、List,Grid,StaggeredGrid类型的正常布局及多布局
②、空白页/头部/尾部
③、加载更多
④、折叠布局(支持多级折叠)
⑤、拖拽、横向滑动删除
⑥、附送两个ItemDecoration,可根据不同需求选择
⑦、采用ObservableList作为数据源,无需手动notify
⑧、支持findViewById,ViewBinding,DataBinding三种模式,可根据你现有项目模式或喜好随意更换!
⑨、动画的高可配置(综合考虑后采用recyclerView的itemAnimator方案,如有需要请自行依赖mikepenz大神的ItemAnimators库)
⑩、吸顶(采用sticky-layoutmanager的方案,低耦合adapter和item,由于原库的position获取有一些bug,便将其集成到本项目中并修复了bug)
2、依赖,最新版本请看github或者jitpack
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.q876625596:YasuoRecyclerViewAdapter:x.y.z'
}
2、示例展示
如果想直接Ctrl CV代码,快速上手的同学,请直接移步sample
3、详细介绍
1)数据源
必须使用YasuoList或其子类作为数据源,YasuoList继承自ObservableArrayList,新增了部分常用方法,并在adapter内部做了监听处理,因此使用该类型数据源可以不用手动notify
2)简单写法(单布局/多布局/header/footer)
fun findViewByIdMode(){
//数据源
val list = YasuoList()
val headerList = YasuoList()
val footerList = YasuoList()
binding.myRV.layoutManager = GridLayoutManager(this, 3)
//findViewById模式
binding.myRV.adapterBinding(this,list){
//do something
//绑定文本布局
//只需要给对应的布局配置holderConfig,即可实现多布局,header,footer
holderConfig(R.layout.item_layout_text, TextBean::class) {
onHolderBind { holder, item ->
holder.getView(R.id.itemText).apply {
text = item.text.value
}
}
}
}
//ViewBinding模式
binding.myRV.adapterViewBinding(this,list){
//do something
//配置文本布局
//只需要给对应的布局配置holderConfig,即可实现多布局,header,footer
holderConfig(R.layout.item_layout_text, TextBean::class, { ItemLayoutTextBinding.bind(it) }) {
onHolderBind { holder, item ->
itemText.text = item.text.value
}
}
}
//DataBinding模式
binding.myRV.adapterDataBinding(this,list){
//do something
//配置文本布局
//只需要给对应的布局配置holderConfig,即可实现多布局,header,footer
holderConfig(R.layout.item_layout_text_data_binding, TextBean::class, ItemLayoutTextDataBindingBinding::class) {
onHolderBind { holder ->
//dataBInding模式已在xml中绑定了数据,无需手动设置
}
}
}
}
以上三种模式的差异就只有这么一点,相互切换也相当的方便。
3)空布局
空布局的使用也非常简单,先将空布局的holderConfig配置之后,再调用adapter.showEmptyLayout就行了。
binding.myRV.adapterViewBinding(this,list){
//do something
holderConfig(R.layout.item_layout_text, TextBean::class, { ItemLayoutTextBinding.bind(it) }) {
onHolderBind { holder, item ->
itemText.text = item.text.value
itemText.setOnClickListener {
showEmptyLayout(/*空布局实体*/EmptyBeanTwo(), /*是否清空header*/true, /*是否清空footer*/true)
}
}
}
}
4)对布局设置占比
设置占比有两种方式,第一种,给一种类型的布局设置占比:
binding.myRV.adapterViewBinding(this,list){
//do something
holderConfig(R.layout.item_layout_text, TextBean::class, { ItemLayoutTextBinding.bind(it) }) {
//do something
//给某个itemViewType的布局统一设置
//瀑布流占满一行
staggeredGridFullSpan = true
//网格布局占比
gridSpan = 3
}
}
第二种,针对某个item单独设置占比:
list.add(ImageBean(MutableLiveData(ContextCompat.getDrawable(this@MainActivity, R.drawable.eee))).apply {
//给某个item单独设置
//瀑布流占满一行
staggeredGridFullSpan = true
//网格布局占比
gridSpan = 3
}
判断优先级:单个item设置 > 类型设置
5)加载更多
加载更多和空布局类似,也是先将加载更多布局的holderConfig配置之后,再调用adapter.showLoadMoreLayout使空布局显示出来,最后添加adapter.onLoadMoreListener监听即可。
binding.myRV.adapterViewBinding(this,list){
//展示加载更多
showLoadMoreLayout(DefaultLoadMoreItem())
//设置加载更多的监听
onLoadMoreListener(binding.myRV) {
//请求数据...
}
//do something
}
6)拖拽/侧滑删除
只需要使用adapter.enableDragOrSwipe即可启用拖拽,同时也可以设置监听,设置手势方向,以及对某些特定布局禁用等
binding.myRV.adapterViewBinding(this,list){
//拖拽/侧滑删除
enableDragOrSwipe(binding.myRV, isLongPressDragEnable = true, isItemViewSwipeEnable = true)
//do something
}
7)吸顶
首先设置layoutManager:StickyLinearLayoutManager,StickyGridLayoutManager,StickyStaggeredGridLayoutManager
吸顶有两种方式,第一种,对某一个类型的布局设置吸顶
binding.myRV.adapterViewBinding(this,list){
//do something
holderConfig(R.layout.item_layout_text, TextBean::class, { ItemLayoutTextBinding.bind(it) }) {
//给某个itemViewType的布局统一设置
//吸顶,注意,吸顶会默认占满一行
sticky = true
//do something
}
}
第二种,针对某个item设置吸顶
list.add(ImageBean(MutableLiveData(ContextCompat.getDrawable(this@MainActivity, R.drawable.eee))).apply {
//给某个item单独设置
//吸顶,注意,吸顶会默认占满一行
sticky = true
}
判断优先级:单个item设置 > 类型设置
8)折叠布局
折叠布局需要数据类继承YasuoFoldItem,之后只需要使用adapter.expandOrFoldItem来展开/收起即可,支持多级折叠,如果需要删除或添加折叠布局中的某个item,建议使用adapter.removeAndFoldListItem和adapter.addAndFoldListItem方法
9)动画配置
动画采用mikepenz大神的ItemAnimators库,如有需要,请先自行依赖该库。
binding.myRV.itemAnimator = SlideLeftAlphaAnimator()
10)附送的itemDecoration
支持为每条边单独设置样式
binding.myRV.addYasuoDecoration {
setDecoration(R.layout.item_layout_text, this@MainActivity, defaultRes)
setDecoration(R.layout.item_layout_image, this@MainActivity, defaultRes)
}
额外附一个span相等的网格布局专用空白分隔ItemDecoration
binding.myRV.addItemDecoration(GridSpacingItemDecoration(3, 20, true))
4、api展示
1)adapter可配置属性/方法一览
属性名/方法名 | 介绍 | 默认值 |
---|---|---|
itemList | 主体列表 | YasuoList |
headerList | 头部列表 | YasuoList |
footerList | 尾部列表 | YasuoList |
showLoadMoreLayout(loadMoreItem: T) | 配置并显示加载更多布局 | ------ |
removeLoadMore() | 移除加载更多布局 | ------ |
enableLoadMoreListener() | 启用列表滚动到底部时加载更多的监听 | ------ |
disableLoadMoreListener() | 禁用列表滚动到底部时加载更多的监听 | ------ |
isShowEmptyLayout() | 判断当前是否是显示空布局状态 | ------ |
showEmptyLayout(emptyItem: T, clearHeader: Boolean = false, clearFooter: Boolean = false) | 判断当前是否是显示空布局状态 | ------ |
expandOrFoldItem(item: YasuoFoldItem) | 展开/折叠某个item | ------ |
removeAndFoldListItem(childItem: Any, foldList: YasuoList |
移除一个item的同时移除其折叠列表的相同item | ------ |
getAllListSize() | 获取全部列表的长度 | ------ |
getItemListTrueSize() | 获取[itemList]的实际长度 | ------ |
getHeaderListTrueSize() | 获取[headerList]的实际长度 | ------ |
getFooterListTrueSize() | 获取[footerList]的实际长度 | ------ |
getHeaderTruePosition(position: Int) | 获取[headerList]的真实position | ------ |
getItemTruePosition(position: Int) | 获取[itemList]的真实position | ------ |
getFooterTruePosition(position: Int) | 获取[footerList]的真实position | ------ |
inHeaderList(position: Int) | 判断position在[headerList]内 | ------ |
inItemList(position: Int) | 判断position在[itemList]内 | ------ |
inFooterList(position: Int) | 判断position在[footerList]内 | ------ |
setAfterDataChangeListener(listener: () -> Unit) | 列表数据发生改变后的监听,在notify之后触发 | ------ |
enableDragOrSwipe(...) | 设置item是否可拖拽、滑动删除 | ------ |
onLoadMoreListener(...) | 设置加载更多的监听 | ------ |
holderConfig(...) | 配置holder,建立数据类与布局文件之间的匹配关系 | ------ |
2)holderConfig可配置属性/方法一览
属性名/方法名 | 介绍 | 默认值 |
---|---|---|
sticky | 该类型布局是否吸顶 | false |
isFold | 该类型布局是否支持展开折叠 | false |
gridSpan | 该类型布局在grid中的占比 | 0 |
staggeredGridFullSpan | 该类型布局在staggeredGrid中是否占满 | false |
holderCreateListener | 该类型Holder创建时的监听 | null |
holderBindListener | 该类型的Holder绑定时的监听 | null |
createBindingFun | ViewBinding的创建方法,仅ViewBinding模式 | null |
variableId | xml中对应的数据id,仅DataBinding模式 | BR.item |
3)YasuoNormalItem可配置属性/方法一览
属性名/方法名 | 介绍 | 默认值 |
---|---|---|
sticky | 该item是否吸顶 | false |
gridSpan | 该item在grid中的占比 | 0 |
staggeredGridFullSpan | 该item在staggeredGrid中是否占满 | false |
4)YasuoNormalItem可配置属性/方法一览
属性名/方法名 | 介绍 | 默认值 |
---|---|---|
list | 下一级列表 | YasuoList |
isExpand | 是否已展开 | false |
parentHash | 父级hash,展开后才会赋值 | false |
sticky | 该item是否吸顶 | false |
gridSpan | 该item在grid中的占比 | 0 |
staggeredGridFullSpan | 该item在staggeredGrid中是否占满 | false |
三、结语
首先感谢大家的阅读,马上就要过年了,在这里也祝大家新年快乐,希望这个库能够对你们有所帮助。如果你喜欢YasuoRecyclerViewAdapter这个库,希望能在github上给一个star,作为我进步的动力!
如果他有不足或需要新增的功能,可以向我提issue或添加我的qq:876625596