简单易懂的 RecyclerView 通用 adapter 封装
需要迁移到 AndroidX,封装实现方法很简单,代码也很少。
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
add the dependency to your build.gradle:
kotlinx.android.synthetic (LayoutContainer) Version: v1.0
// ViewBinding Version
implementation 'com.github.nukc:RecyclerAdapter:dsl-v1.2.1'
DSL 写法
// 返回 adapter
recycler_view.setup(LinearLayoutManager(this)) {
hasStableIds = true
renderItem<Int, ItemPureBinding> {
res(R.layout.item_pure)
getViewBinding = {
ItemPureBinding.bind(it)
}
}
renderItem<NumberItem, ItemLeftBinding> {
res(R.layout.item_left, R.layout.item_right) // 支持同个类型多个布局
getViewBinding = {
ItemLeftBinding.bind(it)
}
getItemViewType {
when (data.number % 2) {
0 -> R.layout.item_left
else -> R.layout.item_right
}
}
bind {
// 可在这里更新视图
binding.tvText.text = data.number.toString()
}
partialUpdate {
// payloads 不为空的时候,在此局部更新
}
}
renderItem<List<Banner>, ViewBannerBinding> {
type = Banner::class.java // 当 item 的数据是数组,需要设置 type
getViewBinding = {
ViewBannerBinding.bind(it)
}
res(R.layout.view_banner) {
// 可在这里对试图进行设置,比如点击事件
}
bind {
// ...
}
// ... 还有对应 Adapter 的其它一些方法
}
}
常规写法
recycler_view.adapter = RecyclerAdapter.explosion()
.register(bannerProvider)
.register(chosenProvider)
.register(object : PureLayoutProvider<Int>(Integer::class.java) {
override fun getLayoutResId(): Int {
return R.layout.item_pure
}
override fun initHolder(holder: RecyclerView.ViewHolder, itemView: View) {
itemView.findViewById<View>(R.id.layout_likest).setOnClickListener {
// do something
}
// ..
}
})
.register(multiProvider)
.setItems(arrayListOf(banners, arrayListOf(chosen), 1))
.build()
BaseProvider,以下为具体实现类
-
PureLayoutProvider 纯布局,不用绑定数据
-
SimpleProvider 不想自定义 ViewHolder(在 bind() 方法中 findViewById)
-
HolderProvider 大多数需求都可直接用此 Provider
-
MultiTypeProvider 遇到同个数据类型且有多个 viewType 的时候(比如聊天界面)
object : PureLayoutProvider<Int>(Integer::class.java) {
override fun getLayoutResId(): Int {
return R.layout.item_pure
}
override fun initHolder(holder: RecyclerView.ViewHolder, itemView: View) {
itemView.findViewById<View>(R.id.layout_likest).setOnClickListener {
// do something
}
// ..
}
}
Model and Viewholder
public class NumberItem {
private int number;
public NumberItem(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
private class MultiHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvText: TextView = view.findViewById(R.id.tv_text)
var data: NumberItem? = null
init {
itemView.setOnClickListener {
data?.let {
// do something
}
}
}
}
provider
private val multiProvider = object
: MultiTypeProvider<NumberItem, MultiHolder>(NumberItem::class.java) {
/**
* 需要先提供全部类型的 layoutResId
* @see Builder.register
*/
override fun providerAllLayoutResId(): IntArray {
return intArrayOf(R.layout.item_left, R.layout.item_right)
}
/**
* 根据 position 或 data 返回该位置的 layoutResId,同时当做该 item 的 view Type
* @see RecyclerAdapter.getItemViewType
*/
override fun getLayoutResId(position: Int, data: NumberItem): Int {
return when (data.number % 2) {
0 -> R.layout.item_left
else -> R.layout.item_right
}
}
/**
* 可根据 viewType 返回 ViewHolder
* @param itemView Inflate a new view hierarchy from the viewType
* @param viewType = getLayoutResId
*/
override fun provideHolder(itemView: View, viewType: Int): MultiHolder {
return MultiHolder(itemView)
}
override fun bind(holder: MultiHolder, data: NumberItem) {
holder.data = data
holder.tvText.text = data.number.toString()
}
}
Provider: 其它一些可覆写方法
fun getItemId(position: Int): Long = position.toLong()
fun onViewRecycled(holder: VH)
fun onFailedToRecycleView(holder: VH): Boolean = false
fun onViewAttachedToWindow(holder: VH)
fun onViewDetachedFromWindow(holder: VH)
Adapter: 之后都执行响应的 notify 方法
方法名 | 备注 |
---|---|
refresh(items) | 清空原先的数据再加入新的数据后刷新 |
add(position, item) | 在指定位置插入 |
add(item) | 在最后位置插入 |
addAll(positionStart, items) | 在指定开始位置插入一个集合 |
addAll(items) | 在最后位置插入一个集合 |
move(fromPosition, toPosition) | 把 fromPosition 的 item 移动到 toPosition |
change(position, item) | 改变指定位置的数据,然后刷新 item |
remove(position) | 移除指定位置的 item |
clear() | 清空 |
Apache License, Version 2.0