作者簡介 原創微信公眾號郭霖 WeChat ID: guolin_blog
大家周五好,提前祝大家周末愉快!
本篇來自老司機張旭童投稿,繼續給大家帶來了原創的開源庫。本文是此開源庫系列的第二篇(主要涉及DataBinding),所以文中的上文指系列的第一篇,想從頭了解的朋友可以訪問他的博客查看。
張旭童的博客地址:
http://blog.csdn.net/zxt0601
前言
在上文中,我們利用 Adapter模式 封裝了一個庫,能快速為 任意ViewGroup 添加 子View。有如下特點:
快速簡單使用
支持任意ViewGroup
無耦合
無侵入性
Item支持多種類型
在庫中V1.1.0版本,我也順手加入了 RecyclerView、ListView、GridView 的通用 Adapter 功能,庫地址:
https://github.com/mcxtzhang/all-base-adapter
現在V1.2.0版本發布,我又加入了我最近超愛的一個技術,DataBinding。
封裝了一套一行代碼實現花式列表的Adapter。即利用 DataBinding 實現 RecyclerView 中快速使用的 Adapter。
以后不管寫多種type還是單type的列表,利用?DataBinding?和?本庫,都只需要一行代碼!
這里也算是安利 DataBinding 吧,真的超好用。還沒使用的朋友們,在看到本文可以如此簡單寫花式列表后,建議去學習一下。先看用法吧,簡單粗暴到沒朋友。
用法
使用必讀
BaseBindingAdapter?利用 DataBinding 提供的動態綁定技術,使用?BR.data?封裝數據、BR.itemP?封裝點擊事件。所以對?layout 有以下要求:
layout中 數據name 起名data
layout中 點擊事件Presenter 起名 itemP
比如:
1. 單Item列表
效果如圖,順帶演示了 BaseBindingAdapter 封裝的一些增刪功能:
用法:
和其他 BaseAdapter 用法一致
構造函數只需要傳入 context,datas,layout
mAdapter=newBaseBindingAdapter(this, mDatas,R.layout.item_db_single);
好了,列表已經出來了。我不騙你,就這一句話。如果需要設置點擊事件(點擊事件設置所有類型都一樣,下不贅述):
特殊需求:如果有特殊需求,可傳入兩個泛型,重寫onBindViewHolder搞事情:
2. 多Item同種數據類型列表
一般是像IM那種列表,雖然Item不同,但是數據結構是同一個。用法,一句話~效果如圖:
用法:
數據結構(JavaBean)需實現?IBaseMulInterface接口,根據情況返回不同的layout。
構造函數只需要傳入context,datas.
mAdapter=newBaseMulTypeBindingAdapter(this, mDatas);
復雜列表依然一句話:
特殊需求:如果有特殊需求,可傳入數據結構的泛型,避免強轉,重寫?onBindViewHolder()?方法,但是 Binding類 不可避免的需要強轉了:
3. 多Item、多種數據類型列表
各大APP首頁,Banner、列表、推薦混排,數據結構肯定不同,但是依然只要一句代碼搞定Adapter!效果如圖:
用法:
數據結構(JavaBean)需分別實現?IBaseMulInterface接口,返回數據結構對應的layout。
構造函數只需要傳入context,datas.
mAdapter=newBaseMulTypeBindingAdapter(this, mDatas);
特殊需求:如果有特殊需求,重寫?onBindViewHolder()方法,但是 數據結構 和 Binding類 都不可避免的需要強轉了:
4. 不能忘了上文的ViewGroup
對上文封裝的 ViewGroup 類型 Adapter 也提供 DataBinding 的支持。當然還是流式布局搭配我自己的側滑菜單控件。效果如圖:
用法:和上文一樣,只是 Adapter 換成?SingleBindingAdapter
如果需要設置點擊事件:
mAdapter.setItemPresenter(newItemDelPresenter());
設計思路與實現
使用起來如此爽快,其實寫起來也很簡單。
注意 類BaseBindingAdapter?和?BaseMulTypeBindingAdapter?都不是?abstract?的,這說明我們不需要重寫任何方法。
利用 DataBinding,我們在 BasexxxAdapter內部 和 xml 分別做View的創建和數據綁定的工作。
UML類圖
先簡要概括:
BaseBindingVH?繼承自?RecyclerView.ViewHolder,持有?T extends ViewDataBinding類型的?mBinding?變量。利用?ViewDataBinding?我們將不用再寫任何?ViewHolder。
BaseBindingAdapter,繼承自?RecyclerView.Adapter,依賴?BaseBindingVH,onCreateViewHolder(ViewGroup parent, int viewType)方法 返回?BaseBindingVH?作為?ViewHolder。
內部持有三個重要變量:數據對應layout,數據集,Item點擊事件處理類。數據對應layout 會在?onCreateViewHolder(ViewGroup parent, int viewType)?用到。剩下兩個變量在?onBindViewHolder()?用到。對外暴漏?setItemPresenter(Object itemPresenter)供設置點擊事件處理類。
IBaseMulInterface接口 和上文提到的一樣,返回某個數據結構對應的layout,除此之外,本文還有一個十分tricky之處,利用返回的?R.layout.itemxxxx?作為?ItemViewType,在?BaseMulTypeBindingAdapter?會用到。
BaseMulTypeBindingAdapter?繼承自?BaseBindingAdapter,但是它不再關心?mLayoutId?變量,它利用?IBaseMulInterface接口 返回的?R.layout.itemxxxx?作為?ItemViewType,這樣在?onCreateViewHolder(ViewGroup parent, int viewType)?的時候,就可以直接用?viewType?構造出?ItemView。不再依賴?mLayoutId?變量。這是一個我很得意的設計,我在"優雅為RecyclerView增加HeaderView"一文中,也曾用過這個方法。
BaseBindingVH
BaseBindingVH?算是一個核心類,但是又十分簡單。它繼承自?RecyclerView.ViewHolder,持有由泛型傳入的?T extends ViewDataBinding?類型的mBinding變量。
唯一構造函數,需要一個?T t?變量,然后調用?super()?傳入?t.getRoot()?完成?itemView?的賦值。同時對?mBinding?變量賦值。對外暴漏?getBinding()?返回?mBinding?變量。
利用?ViewDataBinding?我們將不用再寫任何?ViewHolder。
BaseBindingAdapter
BaseBindingAdapter,繼承自?RecyclerView.Adapter,依賴?BaseBindingVH,將?BaseBindingVH?作為泛型傳給?RecyclerView.Adapter。
同時?BaseBindingAdapter?本身接受兩個泛型,。
泛型沒有特殊需求可以不傳
泛型D:是Bean類型,如果有就傳。
泛型B:是對應的xml Layout的Binding類
傳入不傳入泛型的區別已經在第二節具體用法里進行了演示,不再贅述。內部持有三個重要變量:
數據對應layout?int mLayoutId;
數據集?List mDatas;
Item點擊事件處理類。Object ItemPresenter;
mLayoutId?和?mDatas?都由構造函數傳入,沒啥好說的。
對外暴漏?setItemPresenter(Object itemPresenter)?供設置點擊事件處理類?ItemPresenter。ItemPresenter?是?Object?類型,這樣才不care你set的Item點擊事件處理類是什么鬼。
onCreateViewHolder(ViewGroup parent, int viewType)?方法返回?BaseBindingVH?作為?ViewHolder。
mLayoutId?會在?onCreateViewHolder(ViewGroup parent, int viewType)?用到,再根據泛型B強轉成對應的?ViewDataBinding:
會在?onBindViewHolder()?方法里,利用 DataBinding 動態綁定?ViewDataBinding.setVariable(BR.itemP, ItemPresenter);為每個Item設置點擊事件。
同時,數據也是同樣在里面綁定的:setVariable(BR.data, mDatas.get(position))。重點代碼如下:
BaseBindingAdapter 內部也封裝了如下方法,方便數據刷新,增刪(定向刷新)調用:
IBaseMulInterface接口
IBaseMulInterface接口 和上文提到的一樣,返回某個數據結構對應的layout.
除此之外,本文還有一個十分tricky之處,利用返回的?R.layout.itemxxxx?作為?ItemViewType,在?BaseMulTypeBindingAdapter?會用到。因為不同的?R.layout.itemxxxx?對于 RecyclerView 來說一定是不同的Item。
BaseMulTypeBindingAdapter
多種ItemType的Base類
BaseMulTypeBindingAdapter?繼承自?BaseBindingAdapter,但是它不再關心?mLayoutId?變量。因此它傳給父類的 泛型B 就是?ViewDataBinding類 本身。解釋如下:
基類的泛型B:不用傳,因為多種 ItemType 肯定 Layout 長得不一樣,那么 Binding類 也不一樣,傳入沒有任何意義
泛型T:多Item 多Bean 情況可以不傳。如果只有一種Bean類型,可以傳入Bean,實現 IBaseMulInterface接口。或者傳入 IBaseMulInterface接口,可以拿到 ?getItemLayoutId(),但是通過 getItemViewType(int position) 一樣。所以多Item多Bean建議不傳。傳入不傳入泛型的區別已經在第二節具體用法里進行了演示,不再贅述。
getItemViewType()?直接返回?IBaseMulInterface接口 的返回值。
在?onCreateViewHolder(ViewGroup parent, int viewType)?的時候,直接用?viewType?構建?ViewDataBinding(ItemView)。不再依賴?mLayoutId?變量。
完整代碼如下:
ViewGroup Adapter的實現
單item
繼承 SingleAdapter,增加 ItemPresenter,在 getView() 完成View創建和綁定。
多Item
更簡單了,繼承 SingleBindingAdapter。重寫getView()即可:
總結
本文利用?DataBinding?的?ViewDataBinding?直接略去寫?ViewHolder。
利用?Object類型 的?ItemPresenter,兼容解決了點擊事件的設置。
最得意的設計,還是利用?R.layout.xxxx?這些布局文件?int類型 的 RID,作為?ItemViewType,一箭雙雕。
DataBinding?很強,希望大家快點擁抱它。
to do list
ViewGroup Adapter 考慮加入復用緩存池
ViewGroup Adapter ,考慮替換onBindView()的ItemView->通用的ViewHolder,這樣可以少寫一些findViewById()代碼
整合 DataBinding 的通用Adapter入庫。(已完成)
完善 RecyclerView、ListView的通用Adapter,支持多種ItemViewType。
加入一些自定義ViewGroup入庫,例如流式布局,九宮格,Banner輪播圖。
完。。。。。。。。。。。。。。。。。。。。。
文章原創作者GuoLin 書籍推薦
郭林大神原創android 書籍:《第一行代碼 android》