强大而灵活的RecyclerView Adapter——BRVAH(框架引入与BaseQuickAdapter使用篇)
theme: channing-cyan
本文正在参加「金石计划 . 瓜分6万现金大奖」
前言
接触到BRVAH是因为我们开发项目中就用到它的BaseQuickAdapter,写Adapter的确好用,不过一看版本是2x的,所以去框架发布Github官方代码库(CymChad/BaseRecyclerViewAdapterHelper: BRVAH:Powerful and flexible RecyclerAdapter (github.com))学习了一下最新的4x版本。下面我们就来看看最新的BRVAH如何使用。
正篇
概况
BRVAH (recyclerview.org)是可以在Android中更方便实现Adapter的RecyclerAdapter框架,它的引入可以节省大量开发时间,
它封装了许多好用的功能,如:点击事件、数据操作、动画、空视图,加载更多等
引入框架
目前该框架已经更新到4x版本,但需要注意这个框架从2x到3x已经不完全兼容,而3x到4x也是不兼容的,但4x有着前几代都没有的优势,它引入更容易,因为v4版本已经上传 maven 中央仓库,不需要再引入三方仓库配置了。
Gradle
implementation "io.github.cymchad:BaseRecyclerViewAdapterHelper:4.0.0-beta04"
直接引入到app的build.gradle文件中的dependencies依赖中即可
BaseQuickAdapter的使用
本文章Demo更新在AndroidStudyman/StudyDemo: Study demo (github.com)项目中,使用方法参考文档:BaseQuickAdapter · CymChad/BaseRecyclerViewAdapterHelper Wiki (github.com)
引入框架后,我们可以看到BaseQuickAdapter源码如下:
```Kotlin
class AdapterDemo : BaseQuickAdapter
//自定义ViewHolder类
class VH(
parent: ViewGroup,
binding: LayoutPageAdapterDemoBinding = LayoutPageAdapterDemoBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): VH {
// 返回一个 ViewHolder
return VH(parent)
}
override fun onBindViewHolder(holder: VH, position: Int, item: ModelDemoItem?) {
// 设置item数据
item?.getItemName()
}
} ```
上面的代码已更新到(StudyDemo/AdapterDemo.kt at main · AndroidStudyman/StudyDemo (github.com))中
我们创建一个AdapterDemo类去继承BaseQuickAdapter,然后写一个VH类去绑定Viewbinding,可以自定义item数据类型,当然,也可以不用我的例子,使用官方教程中不用ViewBinding的方式去写,使用QuickViewHolder:
```Kotlin
class TestAdapter : BaseQuickAdapter
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): QuickViewHolder {
// 返回一个 ViewHolder
return QuickViewHolder(R.layout.layout_animation, parent)
}
override fun onBindViewHolder(holder: QuickViewHolder, position: Int, item: Status?) {
// 设置item数据
}
}
其中adapter中对应的VH中binding的布局如下:
XML
接下来,这是我写的item列表的属性类:
Kotlin
class ModelDemoItem(
var name : String? = null,
var age: Int) {
fun getItemName() : String? {
return name
}
fun getItemAge() : Int {
return age
}
}
用于设置item列表每项展示的数据:
override fun onBindViewHolder(holder: VH, position: Int, item: ModelDemoItem?) {
// 设置item数据
val name = holder.itemView.findViewById我们在每项中添加了name和age数据,然后在adapter中onBindViewHolder()方法设置到对应布局中:
class ActivityAdapterDemo : AppCompatActivity() {
val tag : String = "ActivityAdapterDemo"
private lateinit var binding : ActivityAdapterDemoBinding
private lateinit var adapterDemo: AdapterDemo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAdapterDemoBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.vAdapterList.layoutManager = LinearLayoutManager(this)
val itemBeans: ArrayList<ModelDemoItem> = ArrayList()
for (i in 0..49) {
itemBeans.add(ModelDemoItem("Name $i", i))
}
adapterDemo = AdapterDemo()
adapterDemo.submitList(itemBeans)
binding.vAdapterList.adapter = adapterDemo
...
}
}
上面的代码就是在我们在RecyclerView中绑定Aapter,并往里面填充数据,我们调用BaseQuickAdapter的submitList方法填充数据,RecyclerView所在的Activity视图布局如下:
XML
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/adapter_demo"
android:textColor="@color/black"
android:textSize="16sp"
app:autoSizeMaxTextSize="16sp"
app:autoSizeMinTextSize="8dp"
app:autoSizeTextType="uniform"
android:maxLines="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="56dp"
android:layout_height="56dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/next"
android:visibility="invisible"/>
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/vAdapterList"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
我们可以在Activity中的adapter实例化对象中调用相应的点击事件,长按事件以及为子项也添加对应的事件监听:
Kotlin
//item 长按事件
adapterDemo.setOnItemLongClickListener { adapter, view, position ->
Log.i(tag, " setOnItemLongClickListener ${adapter.hashCode()}, ${view.tag}, $position ")
val intent = Intent(this, MainActivity ::class.java)
intent.action = Intent.ACTION_VIEW
true
}
//item 子控件点击事件 // 需要传递控件 id adapterDemo.addOnItemChildClickListener(R.id.vName) { adapter, view, position -> Log.i(tag, " addOnItemChildClickListener ${adapter.hashCode()}, ${view.tag}, $position ") Toasty.info( baseContext, "addOnItemChildClickListener!").show() }
//item 子控件长按事件 // 需要传递控件 id adapterDemo.addOnItemChildLongClickListener(R.id.vAge) { adapter, view, position -> Log.i(tag, " addOnItemChildLongClickListener ${adapter.hashCode()}, ${view.tag}, $position ") Toasty.info( baseContext, "addOnItemChildLongClickListener!!").show() true
} ``` 除了设置数据集合的submitList()方法,还有很多十分方便的数据设置方法,如下:
修改某一位置的数据
Kotlin
val item = ModelDemoItem("Name 6", 6)
//修改index为1处的数据
adapterDemo[1] = item
新增数据
```Kotlin // 尾部新增数据 adapterDemo.add(item)
// 在指定位置添加一条新数据 adapterDemo.add(1, item)
//val itemBeans: ArrayList
// 指定位置添加数据集 adapterDemo.addAll(1, itemBeans) ```
删除数据
```Kotlin // 删除数据 adapterDemo.remove(item)
// 删除指定位置数据 adapterDemo.removeAt(1) ```
交换数据位置
Kotlin
// 交换两个位置的数据
adapterDemo.swap(1, 3)
获取Item数据的索引
Kotlin
// 如果返回 -1,表示不存在
adapterDemo.getItemPosition(item)
根据索引,获取Item数据
Kotlin
// 如果返回 null,表示没有数据
adapterDemo.getItem(1)
以上都是数据的操作方法,按需所取就行,但要注意一些方法中数据操作的合理性,防止出现存取过界的情况发生
添加动画
内置了五种动画:
Kotlin
/**
* BaseQuickAdapter.AnimationType.AlphaIn
* BaseQuickAdapter.AnimationType.ScaleIn
* BaseQuickAdapter.AnimationType.SlideInBottom
* BaseQuickAdapter.AnimationType.SlideInLeft
* BaseQuickAdapter.AnimationType.SlideInRight
*/
adapterDemo.setItemAnimation(BaseQuickAdapter.AnimationType.AlphaIn)
源码如下:
AlphaIn:淡入项目的动画,在默认 300 毫秒内以统一速率将 alpha 从默认 0f 更改为 1.0f\
ScaleIn:缩放项目的动画,在默认 300 毫秒内将项目的 scaleX 和 scaleY 从默认的 0.5f 更改为 1.0f。(使用具有默认因子的 DecelerateInterpolator)\
SlideInBottom:让项目从底部滑入的动画。(使用因子为 1.3 的 DecelerateInterpolator)默认持续时间为 400 毫秒。\
SlideInLeft:让项目从左侧滑入的动画。(使用因子为 1.8 的 DecelerateInterpolator)默认持续时间为 400 毫秒。\
SlideInRight:让项目从右侧滑入的动画。(使用因子为 1.8 的 DecelerateInterpolator)默认持续时间为 400 毫秒。\
其中DecelerateInterpolator是一种减速插值器,是一种变化率从很快变慢的插值器。
官方也明确举例可以自定义动画:
```Kotlin class CustomAnimation1 : ItemAnimator { override fun animator(view: View): Animator { // 创建三个动画 val alpha: Animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f) val scaleY: Animator = ObjectAnimator.ofFloat(view, "scaleY", 1.3f, 1f) val scaleX: Animator = ObjectAnimator.ofFloat(view, "scaleX", 1.3f, 1f)
scaleY.interpolator = DecelerateInterpolator()
scaleX.interpolator = DecelerateInterpolator()
// 多个动画组合,可以使用 AnimatorSet 包装
val animatorSet = AnimatorSet()
animatorSet.duration = 350
animatorSet.play(alpha).with(scaleX).with(scaleY)
return animatorSet
}
}
// 设置动画
adapter.itemAnimation = CustomAnimation1()
然后在Adapter类中设置startItemAnimator方法来重写动画执行操作:
Kotlin
override fun startItemAnimator(anim: Animator, holder: RecyclerView.ViewHolder) {
}
``` 还有用于决定是否启用动画的方法:
Kotlin
adapterDemo.animationEnable = true
加载空布局
空视图只会在无数据的情况下显示
-
使用
Layout Id
Kotlin adapterDemo.setEmptyViewLayout(context, R.layout.loading_view)
-
使用
View
mAdapter.emptyView = view
-
注意:如果你使用
GridLayoutManager
,请切换至QuickGridLayoutManager
,否则空布局无法铺满
还有更多用法可以查看官方文档:BaseQuickAdapter · CymChad/BaseRecyclerViewAdapterHelper Wiki · GitHub,已经写的很详细了,只是没有完整的Demo,本文就是依据此文档实现的Demo。
总结
因为工作中开发经常使用到,但没想到内容这么多,这只是最常用的部分,此外,还有多类型布局Adapter等等
不过官方的4x版本也在继续写文档,敬请期待吧,当然也可以去看看官方提供的Demo:BRVAH-v4.apk - 蓝奏云 (lanzouj.com),不过不知道为什么是个APK应用,不是项目形式。
- 安卓开发一年技术小结——安卓开发技术整理
- 安卓Kotlin开发学习——接着看高阶函数
- 兔兔按钮——安卓悬浮按钮
- 兔兔进度条Plus——SeekBar充当Progress
- 安卓基础开发——ReentrantLock的简单使用
- 安卓开发基础——使用RecyclerView
- 安卓开发基础(Java)——TextView的使用
- 安卓开发基础——弱引用的使用
- 安卓开发基础——实现音频文件的播放
- 让UI忙碌的安卓Lottie动画渲染库(二)
- 强大而灵活的RecyclerView Adapter——BRVAH(框架引入与BaseQuickAdapter使用篇)
- 安卓语言基础之Kotlin的面向对象编程
- 安卓语言基础之Kotlin高阶函数——Lambda表达式(二)
- 大放光彩的安卓Jetpack组件-ViewModel(一)
- 安卓语言基础之Kotlin高阶函数——Lambda表达式(一)
- 安卓开发必备——build.gradle文件初探(一)
- 安卓开发学Flutter——Dart语法的一些注意点(第二篇)
- 简单易用的安卓SharedPreferences存储(数据存储系列)
- 安卓开发基础技术——WebView加载网页
- 原汁原味的安卓文件存储(数据存储系列)