- BaseAdapter封裝(一) 簡單封裝
- BaseAdapter封裝(二) Header,footer
- BaseAdapter封裝(三) 空資料佔點陣圖
- BaseAdapter封裝(四) PageHelper
- BaseAdapter封裝(五) ListAdapter
- ListAdapter封裝, 告別Adapter程式碼 (上)
- ListAdapter封裝, 告別Adapter程式碼 (中)
- ListAdapter封裝, 告別Adapter程式碼 (下)
- BaseAdapter封裝(八) Paging 分頁
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, 封裝頭尾 等等! 敬請期待