ListAdapter封裝 (上) - SimpleAdapter

前言:

上一篇文章已經講解 ListAdapter 的基本使用;  這次 我們不再關心 實體型別、Item事件回撥,  編寫統一 DiffCallback,  佈局ID傳入.

使用:

1. 首先新建 BaseItem: 列表實體都會實現此介面.  它是 BaseAdapter 的預設實體型別

interface BaseItem {
/**
* 條目更新標記, 用於 DiffUtil areContentsTheSame
*/
var hasChanged: Boolean /**
* Adapter 中的 ItemType.
* 單型別佈局可以不用關心 該返回值
* 多型別佈局中; 需直接返回佈局Id; 例如: R.layout.item_test
*/
fun getMItemType(): Int = 0
}

2. 再建立實體類,  實現 BaseItem 介面;  除了  hasChanged,  只有一個 title 引數;

class TestEntity(
var title: String? = null,
override var hasChanged: Boolean = false
) : BaseItem

3.編寫通用的 DiffCallback;  實體型別就用 BaseItem 

areItemsTheSame(): 我們選用比較記憶體地址的方式;

areContentsTheSame(): 我們選擇狀態標記方式;

class DiffCallback: DiffUtil.ItemCallback<BaseItem>() {
/**
* 比較兩個條目物件 是否為同一個Item
*/
override fun areItemsTheSame(oldItem: BaseItem, newItem: BaseItem): Boolean {
return oldItem === newItem
} /**
* 再確定為同一條目的情況下; 再去比較 item 的內容是否發生變化;
* 我們使用 狀態標識方式判斷;
* @return true: 代表無變化; false: 有變化;
*/
override fun areContentsTheSame(oldItem: BaseItem, newItem: BaseItem): Boolean {
return !oldItem.hasChanged
}
}

4.接下來是 ViewHolder:  用於 item 繫結資料,及快取控制元件.   我們加入事件處理 handler; 以及重置狀態標記;

open class NewViewHolder(val binding: ViewDataBinding, private val handler: BaseHandler?) : RecyclerView.ViewHolder(binding.root){
open fun bind(item: BaseItem?) {
//重置 狀態標記
item?.hasChanged = false
binding.setVariable(BR.item, item)
binding.setVariable(BR.handler, handler)
binding.executePendingBindings()
}
}

5. Handler : MVVM 模式中 Item事件響應處理類;

基類: BaseHandler   它幾乎只出現在 Adapter相關基類中,省的我們再寫泛型;   要使用還得用它的子類

子類: Handler  提供具體實體泛型.  供佈局檔案使用

/**
* item 事件響應基類, 這類什麼都不用寫
*/
open class BaseHandler /**
* item 事件響應基類, 需提供具體的實體類泛型;
*/
abstract class Handler<T: BaseItem> : BaseHandler() {
abstract fun onClick(view: View, info: T)
}

6.下面是重頭戲了:  BaseAdapter

重頭戲?但它卻如此簡單  [捂臉] (自帶轉義);   只需要傳入 BaseHandler 物件;  並重寫 onBindViewHolder 即可;

我還重寫了 submitList();  因為ListAdapter 提交資料時,會判斷前後資料集合是否為同一記憶體地址;  我們讓它必定以新資料集物件傳入; (雖然個人感覺這樣不對, 但博主還就踩上這坑了 [機智])

abstract class BaseAdapter(
protected val handler: BaseHandler? = null) :
ListAdapter<BaseItem, NewViewHolder>(DiffCallback()) { override fun onBindViewHolder(holder: NewViewHolder, position: Int) {
holder.bind(getItem(position))
} /**
* 重寫 提交資料方法, 讓它必定以新資料集合物件傳入
*/
override fun submitList(list: MutableList<out BaseItem>?) {
val newData = mutableListOf<BaseItem>()
if (list != null) {
newData.addAll(list)
}
super.submitList(newData)
}
}

7. 重頭戲中的重頭來了 SimpleAdapter: 

好吧, 它更簡單.  繼承 BaseAdapter 並傳入 layoutId, 再重寫 onCreateViewHolder 即可;

open class SimpleAdapter(
/**
* 佈局id;
*/
private val layout: Int,
handler: BaseHandler? = null
) :
BaseAdapter(handler) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewViewHolder {
return NewViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context), layout, parent, false
), handler
)
}
}

8. 好了封裝完事.  接下來我們要開始用了!  使用也非常簡單

//只需要傳入  佈局id 及 事件響應 Handler
mAdapter = SimpleAdapter(R.layout.item_test_mvvm, object : Handler<TestEntity>(){
override fun onClick(view: View, info: TestEntity) {
Toast.makeText(mActivity, "點了條目", Toast.LENGTH_SHORT).show()
}
})
mDataBind.rvRecycle.let {
it.layoutManager = LinearLayoutManager(mActivity)
it.adapter = mAdapter
}
val data = mutableListOf(TestEntity("第一條"), TestEntity("第一條"), TestEntity("第一條"), TestEntity("第一條"), TestEntity("第一條"))
mAdapter.submitList(data)

9. 好吧,再貼出我的 佈局檔案:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
<variable
name="item"
type="com.example.kotlinmvpframe.network.entity.TestEntity" />
<variable
name="handler"
type="com.example.kotlinmvpframe.test.testtwo.Handler" />
</data> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:onClick="@{(view) -> handler.onClick(view, item)}"
android:padding="20dp">
<TextView
android:id="@+id/btn2"
style="@style/tv_base_16_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.title}" />
</LinearLayout>
</layout>

好的! over

下一篇再講  多條目型別, 巢狀RecycleView, 封裝頭尾 等等! 敬請期待

回到頂部