DataBinding的使用總結-進階篇(recyclerView)

基礎篇

項目代碼:放在前面以防有人看不到   https://github.com/summerhotready/KotlinCol/tree/bindingOrigin

基礎篇講述的是如何配置和使用db,並提供了穩定版本的參數,下面我們聊一聊使用最普遍的recyclerView是如何使用DB的

我們使用RV一般有兩種情況,單佈局和多佈局,單佈局簡單明晰,就易用性來說比不上ListView,但倘若要做上下移動動畫RV可就實在方便多了,RV的動畫將放在另一篇寫動畫的帖子中總結


單佈局

按照我們之前的書寫方式,一個RecyclerView的展示包括:一個對應的Adapter,Modle,ViewHolder和adapter_item.xml。

組成List<Modle>數組後裝配Adapter,Adapter使用綁定好了的ViewHolder來建立item。

你需要做的是:

1.寫好item.xml佈局,並給各子view賦予modle的值

2.在ViewHolder中引用該Item的Binding並返回mBinding.root以替代ItemsView

3.在adapter的binding中賦值給holder.mBinding中綁定的modle

4.我想說的重點是監聽

網上最多的解釋是建立一個Holder類,通過在xml引用調用,我呢不想這樣,我寫了個接口,然後在xml中引用了,果然也成了。

public interface OnAdapterItemClickListener {
    //type
    int TYPE_EMAIL = 1;
    int TYPE_PHONE = 2;
    void onClickSave(int type,String... value);
    void onClickImportant(int type,String... value);
    void onClickSend(int type,String... values);
}

xml引用

引入

<variable
    name="listener"
    type="com.guoxd.kot.listener.OnAdapterItemClickListener"/>
使用
android:onClick="@{(view)->listener.onClickSend(listener.TYPE_EMAIL,data.email,data.name)}"

實現

要注意的是我還沒找到kotlin中匿名類的寫法,所以我寫了一個類實現了它,順便測試了一下String... 的kotlin實現

class Listener : OnAdapterItemClickListener{
    override fun onClickImportant(type: Int, vararg value: String?) {
        for( str in value){
            Log.i("Listener","onClickImportant Click:"+type+" string:"+str)
        }
    }
    override fun onClickSave(type: Int, vararg value: String?) {
        for( str in value){
            Log.i("Listener","onClickSave Click:"+type+" string:"+str)
        }
    }
    override fun onClickSend(type: Int, vararg values: String?) {
        for( str in values){
            Log.i("Listener","onClickSend Click:"+type+" string:"+str)
        }
    }
}

賦值

adapter.listener = Listener()
Adapter中:

聲明:var listener: OnAdapterItemClickListener?=null;

傳遞:onBindViewHolder中調用 holder?.bindListener(listener)

賦值:ViewHolder中的bindListener函數

fun bindListener(listener : OnAdapterItemClickListener?){
    mBinding.setVariable(BR.listener,listener)
}

多佈局

我參考了簡書上一篇博客,一開始我以爲它是服用Adapter和ViewHolder,來實現多個RecyclerView共用一套Adapter的問題,後來我發現不是,他解決的是一個RecyclerView中使用多種佈局的問題。

我在他文章的基礎上做了改變,對於數據源Bean,提供了抽象類BaseBean,並聲明一個抽象方法:getViewType()用來提供該數據源使用的layout,在我的設計中使用抽象類比原文的聲明接口更好理解和維護。關於接口和抽象類的定論在此不議,僅僅因爲無需再繼承其他的類所以此處用抽象類。

public abstract class BaseBean {
    public abstract int getViewType();//要注意使用public聲明
}
在單佈局的基礎上我們可以製作多佈局,首先最重要的一點,將再ViewHolder中綁定layout的步驟挪到Adapter中,通過傳入ViewDataBinding的子類來實現,並且及其重要的一點,在ViewHolder中需要對滿足某一條件的modle賦值:

open class ContactBean(var name : String,var number : String,var Address : String,var isImportant : Boolean) : BaseBean(){
    override fun getViewType(): Int {//回傳
        return R.layout.adapter_contact_item
    }
    init {
        isImportant = false
    }
}

以上面聯繫人爲例子,編寫ViewHolder

class ViewHolder(val mBinding : ViewDataBinding ) : RecyclerView.ViewHolder(mBinding.root){//替代的是ItemsView
    fun getBinding() : ViewDataBinding {//傳入ViewDataBinding的子類
        return mBinding
    }
    fun bindData(bean:BaseBean){//賦值,BR是DB自動生成的,並看不到,可能會有多個可以相互替代不過選擇根目錄下的BR就可以了
        mBinding.setVariable(BR.data,bean)//這一步是賦值,將BaseBean的實現/子類與data進行綁定,需要注意的是所有的adapter_item.xml的填充數據都要命名爲data
    }
}

需要注意的是BR中的內容需要重新編譯纔會發生改變
綁定,Adapter中首先要重寫getItemViewType,以確保onCreateViewHolder中viewType的值非0.

 override fun getItemViewType(position: Int): Int {
        return mDatas[position].getViewType()
    }


// viewType:重寫getItemViewType後纔不是默認的0
    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
        val binding : ViewDataBinding = DataBindingUtil.inflate(
                LayoutInflater.from(mContext), viewType,parent,false )
        return ViewHolder(binding)
    }

只有重寫了該方法create中獲得的viewType的值纔不會總是 0
這樣一來原本一一對應的adapter和viewholder被抽象出來,binding這一步被放到data中,viewholder反回一整個binding數據,而後在adapter中使用接口將複雜操作在引用中實現。
之後我測試了使用parent?.childCount獲取,但這樣有個問題是隻能呈現出頁面展示的item序號,比如頁面能展示4條,他只會生成5個於是我有個想法,在一個item內寫兩種佈局,引入兩個data,通過判空方式顯示data的值,當你一個頁面有五六種佈局的時候會比較麻煩,所以還是重寫這個方法最好

Adapter複用

下面談一談我真正想說的Adapter的複用,我是想實現一套adapter和viewHolder在多個RecyclerView上的使用,通過上一步驟,解耦了ViewHolder和molder,所以下一步是通過鉤子,將Adapter的onBindViewHolder傳遞到activity中,通過傳遞父類的數據類型,在處理頁面進行對應實現。
參考 MultAdapter,這部分代碼爲什麼不放出?因爲跟詳細講解的多佈局是一樣的,在那基礎上引入了一個listener,要是看不懂去看看代碼吧。
總結一下,複用的越多要寫得越少,留給實現要做得越多。你可能覺得這是廢話,最初我看到的時候也覺得是廢話,等到寫了許多代碼才覺得這是實踐出真知。


發佈了62 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章