本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布转载请标明出处: http://blog.csdn.net/zxt0601/article/details/53618694本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)代码传送门:喜欢的话,随手点个star。多谢 https://github.com/mcxtzhang/all-base-adapter
在前文快速开发偷懒必备(一)中,我们利用Adapter模式封装了一个库,能快速为任意ViewGroup添加子View。有如下特点: * 快速简单使用 * 支持任意ViewGroup * 无耦合 * 无侵入性 * Item支持多种类型
在库中V1.1.0版本,我也顺手加入了RecyclerView、ListView、GridView的通用Adapter功能,库地址在这里。现在V1.2.0版本发布,我又加入了我最近超爱的一个技术,DataBinding。
封装了一套一行代码实现花式列表的Adapter。
即利用DataBinding实现RecyclerView中快速使用的Adapter。
以后不管写多种type还是单type的列表,利用DataBinding 和本库,都只需要一行代码!
这里也算是安利DataBinding吧,真的超好用。还没使用的朋友们,在看到本文可以如此简单写花式列表后,建议去学习一下。先看用法吧,简单粗暴到没朋友。
BaseBindingAdapter利用DataBinding提供的动态绑定技术,使用BR.data封装数据、BR.itemP封装点击事件。所以对layout有以下要求:
如:
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="itemP" type="mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleActivity.SingleItemPresenter"/> <variable name="data" type="mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleBean"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="1dp" android:background="@color/colorAccent" android:onClick="@{v->itemP.onItemClick(data)}" android:orientation="horizontal"> <ImageView android:id="@+id/ivAvatar" android:layout_width="200dp" android:layout_height="200dp" app:netUrl="@{data.avatar}" tools:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{data.name}" tools:text="测试多种"/> </LinearLayout></layout>1234567891011121314151617181920212223242526272829303132
1234567891011121314151617181920212223242526272829303132顺带演示了BaseBindingAdapter封装的一些增删功能。

和其他BaseAdapter用法一致: * 构造函数只需要传入context,datas,layout
mAdapter = new BaseBindingAdapter(this, mDatas, R.layout.item_db_single);1
1好了,列表已经出来了。我不骗你,就这一句话。
如果需要设置点击事件(点击事件设置所有类型都一样,下不赘述):
//★ 设置Item点击事件 mAdapter.setItemPresenter(new SingleItemPresenter());12
12 /** * ★ Item点击事件P */ public class SingleItemPresenter { public void onItemClick(DBSingleBean data) { data.setName("修改之后立刻见效"); } }12345678
12345678如果有特殊需求,可传入两个泛型,重写onBindViewHolder搞事情:
// ★泛型D:是Bean类型,如果有就传。 泛型B:是对应的xml Layout的Binding类 mAdapter = new BaseBindingAdapter<DBSingleBean, ItemDbSingleBinding>(this, mDatas, R.layout.item_db_single) { @Override public void onBindViewHolder(BaseBindingVH<ItemDbSingleBinding> holder, int position) { //★super一定不要删除 super.onBindViewHolder(holder, position); //如果有特殊需求,可传入两个泛型,重写onBindViewHolder搞事情。 ItemDbSingleBinding binding = holder.getBinding(); DBSingleBean data = mDatas.get(position); } };1234567891011
1234567891011一般是像IM那种列表,虽然Item不同,但是数据结构是同一个。用法,一句话~

IBaseMulInterface接口,根据情况返回不同的layout。构造函数只需要传入context,datas. mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);1
1复杂列表依然一句话。
public class MulTypeSingleBean extends BaSEObservable implements IBaseMulInterface { private String avatar; private String name; private boolean receive; @Override public int getItemLayoutId() { if (isReceive()) { return R.layout.item_db_mul_1; } else { return R.layout.item_db_mul_2; } }}12345678910111213
12345678910111213如果有特殊需求,可传入数据结构的泛型,避免强转,重写onBindViewHolder()方法,但是Binding类 不可避免的需要强转了:
12345678910111213141516171819各大APP首页,Banner、列表、推荐混排,数据结构肯定不同,但是依然只要一句代码搞定Adapter!

IBaseMulInterface接口,返回数据结构对应的layout。构造函数只需要传入context,datas. mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);1
1public class MulTypeMulBean1 extends BaseObservable implements IBaseMulInterface { private String avatar; private String name; @Override public int getItemLayoutId() { return R.layout.item_db_mulbean_1; }}123456789
123456789public class MulTypeMulBean2 extends BaseObservable implements IBaseMulInterface { private String background; @Override public int getItemLayoutId() { return R.layout.item_db_mulbean_2; }}12345678
12345678如果有特殊需求,重写onBindViewHolder()方法,但是数据结构 和 Binding类 都不可避免的需要强转了:
12345678910111213141516171819对上文封装的ViewGroup类型Adapter也提供DataBinding的支持。
当然还是流式布局搭配史上集成最叼侧滑菜单控件。

和上文快速开发偷懒必备(一)一样,只是Adapter换成SingleBindingAdapter
1如果需要设置点击事件:
mAdapter.setItemPresenter(new ItemDelPresenter());1
1使用起来如此爽快,其实写起来也很简单。
注意类BaseBindingAdapter和BaseMulTypeBindingAdapter都不是abstract的,这说明我们不需要重写任何方法。
利用DataBinding,我们在BasexxxAdapter内部和xml分别做View的创建和数据绑定的工作。

先简要概括
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算是一个核心类,但是又十分简单。它继承自RecyclerView.ViewHolder,持有由泛型传入的T extends ViewDataBinding类型的mBinding变量。唯一构造函数,需要一个T t变量,然后调用super()传入t.getRoot()完成itemView的赋值。同时对mBinding变量赋值。对外暴漏getBinding()返回mBinding变量。
利用ViewDataBinding我们将不用再写任何ViewHolder。
123456789101112BaseBindingAdapter,继承自RecyclerView.Adapter,依赖BaseBindingVH,将BaseBindingVH作为泛型传给RecyclerView.Adapter。同时BaseBindingAdapter本身接受两个泛型,<D, B extends ViewDataBinding>。
传入不传入泛型的区别已经在第二节具体用法里进行了演示,不再赘述。 内部持有三个重要变量:
数据对应layoutint mLayoutId;数据集 List<D> 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:
1会在onBindViewHolder()方法里,利用DataBinding动态绑定ViewDataBinding.setVariable(BR.itemP, ItemPresenter);为每个Item设置点击事件。同时,数据也是同样在里面绑定的:setVariable(BR.data, mDatas.get(position))。
重点代码如下:
public class BaseBindingAdapter<D, B extends ViewDataBinding> extends RecyclerView.Adapter<BaseBindingVH<B>> { protected Context mContext; protected int mLayoutId; protected List<D> mDatas; protected LayoutInflater mInfalter; //用于设置Item的事件Presenter protected Object ItemPresenter; public BaseBindingAdapter(Context mContext, List mDatas, int mLayoutId) { this.mContext = mContext; this.mLayoutId = mLayoutId; this.mDatas = mDatas; this.mInfalter = LayoutInflater.from(mContext); } @Override public BaseBindingVH<B> onCreateViewHolder(ViewGroup parent, int viewType) { BaseBindingVH<B> holder = new BaseBindingVH<B>((B) DataBindingUtil.inflate(mInfalter, mLayoutId, parent, false)); onCreateViewHolder(holder); return holder; } /** * 如果需要给Vh设置监听器啥的 可以在这里 * * @param holder */ public void onCreateViewHolder(BaseBindingVH<B> holder) { } /** * 子类除了绑定数据,还要设置监听器等其他操作。 * 可以重写这个方法,不要删掉super.onBindViewHolder(holder, position); * * @param holder * @param position */ @Override public void onBindViewHolder(BaseBindingVH<B> holder, int position) { holder.getBinding().setVariable(BR.data, mDatas.get(position)); holder.getBinding().setVariable(BR.itemP, ItemPresenter); holder.getBinding().executePendingBindings(); } /** * 用于设置Item的事件Presenter * * @param itemPresenter * @return */ public BaseBindingAdapter setItemPresenter(Object itemPresenter) { ItemPresenter = itemPresenter; return this; }}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556BaseBindingAdapter内部也封装了如下方法,方便数据刷新,增删(定向刷新)调用:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687来点简单的.
IBaseMulInterface接口和快速开发偷懒必备(一)提到的一样,返回某个数据结构对应的layout.
除此之外,本文还有一个十分tricky之处,利用返回的R.layout.itemxxxx作为ItemViewType,在BaseMulTypeBindingAdapter会用到。因为不同的R.layout.itemxxxx对于RecyclerView来说一定是不同的Item,
多种ItemType的Base类
BaseMulTypeBindingAdapter继承自BaseBindingAdapter,但是它不再关心mLayoutId变量。因此它传给父类的泛型B就是ViewDataBinding类本身。解释如下:* 基类的泛型B:不用传,因为多种ItemType 肯定Layout长得不一样,那么Binding类也不一样,传入没有任何意义
getItemViewType()直接返回 IBaseMulInterface接口的返回值。
在onCreateViewHolder(ViewGroup parent, int viewType)的时候,直接用viewType构建ViewDataBinding(ItemView)。不再依赖mLayoutId变量。这是一个我很得意的设计,我在优雅为RecyclerView增加HeaderView一文中,也曾用过这个方法添加头部。
完整代码如下:
public class BaseMulTypeBindingAdapter<T extends IBaseMulInterface> extends BaseBindingAdapter<T, ViewDataBinding> { public BaseMulTypeBindingAdapter(Context mContext, List<T> mDatas) { super(mContext, mDatas); } @Override public int getItemViewType(int position) { return mDatas.get(position).getItemLayoutId(); } @Override public BaseBindingVH<ViewDataBinding> onCreateViewHolder(ViewGroup parent, int viewType) { BaseBindingVH<ViewDataBinding> holder = new BaseBindingVH<ViewDataBinding>(DataBindingUtil.inflate(mInfalter, viewType, parent, false)); onCreateViewHolder(holder); return holder; }}123456789101112131415161718
123456789101112131415161718继承SingleAdapter,增加ItemPresenter,在getView()完成View创建和绑定。
1234567891011121314151617181920212223242526272829303132333435更简单了,继承SingleBindingAdapter。重写getView()即可。
1234567891011121314151617代码传送门:喜欢的话,随手点个star。多谢 https://github.com/mcxtzhang/all-base-adapter
本文利用DataBinding的ViewDataBinding直接略去写ViewHolder。
利用Object类型的ItemPresenter,兼容解决了点击事件的设置。
最得意的设计,还是利用R.layout.xxxx这些布局文件int类型的的RID,作为ItemViewType,一箭双雕。
DataBinding很强,希望大家快点拥抱它。
onBindView()的ItemView->通用的ViewHolder,这样可以少写一些findViewById()代码转载请标明出处: http://blog.csdn.net/zxt0601/article/details/53618694本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)代码传送门:喜欢的话,随手点个star。多谢 https://github.com/mcxtzhang/all-base-adapter
新闻热点
疑难解答