android 带加号九宫格,快速开发偷懒必备(二) 支持DataBinding啦~爽炸,花式列表一行实现...

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

概述

在前文快速开发偷懒必备(一)中,我们利用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中 数据name起名data

layout中 点击事件Presenter起名 itemP

如:

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools">

name="itemP"

type="mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleActivity.SingleItemPresenter"/>

name="data"

type="mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleBean"/>

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">

android:id="@+id/ivAvatar"

android:layout_width="200dp"

android:layout_height="200dp"

app:netUrl="@{data.avatar}"

tools:src="@mipmap/ic_launcher"/>

android:id="@+id/tvName"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@{data.name}"

tools:text="测试多种"/>

1 单Item列表

效果如图:

顺带演示了BaseBindingAdapter封装的一些增删功能。

351c3b9150af9c49db0c.gif单Item

用法:

和其他BaseAdapter用法一致:构造函数只需要传入context,datas,layoutmAdapter = new BaseBindingAdapter(this, mDatas, R.layout.item_db_single);

好了,列表已经出来了。我不骗你,就这一句话。

如果需要设置点击事件(点击事件设置所有类型都一样,下不赘述)://★ 设置Item点击事件

mAdapter.setItemPresenter(new SingleItemPresenter());/**

* ★ Item点击事件P

*/

public class SingleItemPresenter {

public void onItemClick(DBSingleBean data) {

data.setName("修改之后立刻见效");

}

}

特殊需求:

如果有特殊需求,可传入两个泛型,重写onBindViewHolder搞事情:// ★泛型D:是Bean类型,如果有就传。  泛型B:是对应的xml Layout的Binding类

mAdapter = new BaseBindingAdapter(this, mDatas, R.layout.item_db_single) {

@Override

public void onBindViewHolder(BaseBindingVH holder, int position) {                //★super一定不要删除

super.onBindViewHolder(holder, position);                //如果有特殊需求,可传入两个泛型,重写onBindViewHolder搞事情。

ItemDbSingleBinding binding = holder.getBinding();

DBSingleBean data = mDatas.get(position);

}

};

2 多Item同种数据类型列表

一般是像IM那种列表,虽然Item不同,但是数据结构是同一个。用法,一句话~

效果如图:

313537700b8df9546563.gif多Item同数据结构

用法:数据结构(JavaBean)需实现IBaseMulInterface接口,根据情况返回不同的layout。

构造函数只需要传入context,datas.mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);

复杂列表依然一句话。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;

}

}

}

特殊需求:

如果有特殊需求,可传入数据结构的泛型,避免强转,重写onBindViewHolder()方法,但是Binding类 不可避免的需要强转了:mAdapter = new BaseMulTypeBindingAdapter(this, mDatas) {

@Override

public void onBindViewHolder(BaseBindingVH holder, int position) {                super.onBindViewHolder(holder, position);                //如果有特殊需求,可传入数据结构的泛型,避免强转

MulTypeSingleBean data = mDatas.get(position);                //Binding类 不可避免的需要强转了

ViewDataBinding binding = holder.getBinding();                switch (data.getItemLayoutId()) {                    case R.layout.item_db_mul_1:

ItemDbMul1Binding itemDbMul1Binding = (ItemDbMul1Binding) binding;                        break;                    case R.layout.item_db_mul_2:

ItemDbMul2Binding itemDbMul2Binding = (ItemDbMul2Binding) binding;                        break;

}

}

};

3 多Item、多种数据类型列表

各大APP首页,Banner、列表、推荐混排,数据结构肯定不同,但是依然只要一句代码搞定Adapter!

效果如图:

95751bd9fee55859e107.gif多Item、多数据结构

用法:数据结构(JavaBean)需分别实现IBaseMulInterface接口,返回数据结构对应的layout。

构造函数只需要传入context,datas.mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);public class MulTypeMulBean1 extends BaseObservable implements IBaseMulInterface {

private String avatar;

private String name;

@Override

public int getItemLayoutId() {        return R.layout.item_db_mulbean_1;

}

}public class MulTypeMulBean2 extends BaseObservable implements IBaseMulInterface {

private String background;

@Override

public int getItemLayoutId() {        return R.layout.item_db_mulbean_2;

}

}

特殊需求:

如果有特殊需求,重写onBindViewHolder()方法,但是数据结构 和 Binding类 都不可避免的需要强转了:mAdapter = new BaseMulTypeBindingAdapter(this, mDatas) {

@Override

public void onBindViewHolder(BaseBindingVH holder, int position) {                super.onBindViewHolder(holder, position);                //如果有特殊需求 重写onBindViewHolder方法

// 数据结构 和 Binding类 都不可避免的需要强转了

ViewDataBinding binding = holder.getBinding();                switch (getItemViewType(position)) {                    case R.layout.item_db_mul_1:

ItemDbMul1Binding itemDbMul1Binding = (ItemDbMul1Binding) binding;

MulTypeMulBean1 data1 = (MulTypeMulBean1) mDatas.get(position);                        break;                    case R.layout.item_db_mul_2:

ItemDbMul2Binding itemDbMul2Binding = (ItemDbMul2Binding) binding;

MulTypeMulBean2 data2 = (MulTypeMulBean2) mDatas.get(position);                        break;

}

}

};

4 不能忘了上文的ViewGroup呀

对上文封装的ViewGroup类型Adapter也提供DataBinding的支持。

效果如图:

45a0e2cd9ee07230389b.gif

用法:

和上文快速开发偷懒必备(一)一样,只是Adapter换成SingleBindingAdaptermAdapter = new SingleBindingAdapter<>(this, mDatas = iniDatas(), R.layout.item_db_flow_swipe);

如果需要设置点击事件:mAdapter.setItemPresenter(new ItemDelPresenter());

设计思路与实现

使用起来如此爽快,其实写起来也很简单。

注意类BaseBindingAdapter和BaseMulTypeBindingAdapter都不是abstract的,这说明我们不需要重写任何方法。

利用DataBinding,我们在BasexxxAdapter内部和xml分别做View的创建和数据绑定的工作。

UML类图

3ffb2e104afbdf53e89c.pngUML类图

先简要概括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。public class BaseBindingVH extends RecyclerView.ViewHolder {

protected final T mBinding;

public BaseBindingVH(T t) {        super(t.getRoot());

mBinding = t;

}

public T getBinding() {        return mBinding;

}

}

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:BaseBindingVH holder = new BaseBindingVH((B) DataBindingUtil.inflate(mInfalter, mLayoutId, parent, false));

会在onBindViewHolder()方法里,利用DataBinding动态绑定ViewDataBinding.setVariable(BR.itemP, ItemPresenter);为每个Item设置点击事件。同时,数据也是同样在里面绑定的:setVariable(BR.data, mDatas.get(position))。

重点代码如下:public class BaseBindingAdapter extends RecyclerView.Adapter> {

protected Context mContext;

protected int mLayoutId;

protected List 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 onCreateViewHolder(ViewGroup parent, int viewType) {

BaseBindingVH holder = new BaseBindingVH((B) DataBindingUtil.inflate(mInfalter, mLayoutId, parent, false));

onCreateViewHolder(holder);        return holder;

}    /**

* 如果需要给Vh设置监听器啥的 可以在这里

*

* @param holder

*/

public void onCreateViewHolder(BaseBindingVH holder) {

}    /**

* 子类除了绑定数据,还要设置监听器等其他操作。

* 可以重写这个方法,不要删掉super.onBindViewHolder(holder, position);

*

* @param holder

* @param position

*/

@Override

public void onBindViewHolder(BaseBindingVH 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;

}

}

BaseBindingAdapter内部也封装了如下方法,方便数据刷新,增删(定向刷新)调用:/**

* 刷新数据,初始化数据

*

* @param list

*/

public void setDatas(List list) {        if (this.mDatas != null) {            if (null != list) {

List temp = new ArrayList();

temp.addAll(list);                this.mDatas.clear();                this.mDatas.addAll(temp);

} else {                this.mDatas.clear();

}

} else {            this.mDatas = list;

}

notifyDataSetChanged();

}    /**

* 删除一条数据

* 会自动定向刷新

*

* @param i

*/

public void remove(int i) {        if (null != mDatas && mDatas.size() > i && i > -1) {

mDatas.remove(i);

notifyItemRemoved(i);

}

}    /**

* 添加一条数据 至队尾

* 会自动定向刷新

*

* @param data

*/

public void add(D data) {        if (data != null && mDatas != null) {

mDatas.add(data);

notifyItemInserted(mDatas.size());

}

}    /**

* 在指定位置添加一条数据

* 会自动定向刷新

* 如果指定位置越界,则添加在队尾

*

* @param position

* @param data

*/

public void add(int position, D data) {        if (data != null && mDatas != null) {            if (mDatas.size() > position && position > -1) {

mDatas.add(position, data);

notifyItemInserted(position);

} else {

add(data);

}

}

}    /**

* 加载更多数据

*

* @param list

*/

public void addDatas(List list) {        if (null != list) {

List temp = new ArrayList();

temp.addAll(list);            if (this.mDatas != null) {                this.mDatas.addAll(temp);

} else {                this.mDatas = temp;

}

notifyDataSetChanged();

}

}

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变量。这是一个我很得意的设计,我在优雅为RecyclerView增加HeaderView一文中,也曾用过这个方法添加头部。

完整代码如下:public class BaseMulTypeBindingAdapter extends BaseBindingAdapter {

public BaseMulTypeBindingAdapter(Context mContext, List mDatas) {        super(mContext, mDatas);

}

@Override

public int getItemViewType(int position) {        return mDatas.get(position).getItemLayoutId();

}

@Override

public BaseBindingVH onCreateViewHolder(ViewGroup parent, int viewType) {

BaseBindingVH holder = new BaseBindingVH(DataBindingUtil.inflate(mInfalter, viewType, parent, false));

onCreateViewHolder(holder);        return holder;

}

}

ViewGroup Adapter的实现

单item

继承SingleAdapter,增加ItemPresenter,在getView()完成View创建和绑定。public class SingleBindingAdapter extends SingleAdapter {    //用于设置Item的事件Presenter

protected Object ItemPresenter;    /**

* 用于设置Item的事件Presenter

*

* @param itemPresenter

* @return

*/

public SingleBindingAdapter setItemPresenter(Object itemPresenter) {

ItemPresenter = itemPresenter;        return this;

}

public SingleBindingAdapter(Context context, List datas, int itemLayoutId) {        super(context, datas, itemLayoutId);

}    //重写利用DataBinding做

@Override

public View getView(ViewGroup parent, int pos, D data) {

ViewDataBinding binding = DataBindingUtil.inflate(mInflater, mItemLayoutId, parent, false);

View itemView = binding.getRoot();

onBindView(parent, itemView, data, pos);

binding.setVariable(BR.data, data);

binding.setVariable(BR.itemP, ItemPresenter);        return itemView;

}    //空实现即可,因为DataBinding的实现都是在xml里做

@Override

public void onBindView(ViewGroup parent, View itemView, D data, int pos) {

}

}

多Item:

更简单了,继承SingleBindingAdapter。重写getView()即可。public class MulTypeBindngAdapter extends SingleBindingAdapter {

public MulTypeBindngAdapter(Context context, List datas) {        super(context, datas, -1);

}    //重写利用DataBinding做

@Override

public View getView(ViewGroup parent, int pos, T data) {

ViewDataBinding binding = DataBindingUtil.inflate(mInflater, data.getItemLayoutId(), parent, false);

View itemView = binding.getRoot();

onBindView(parent, itemView, data, pos);

binding.setVariable(BR.data, data);

binding.setVariable(BR.itemP, ItemPresenter);        return itemView;

}

}

总结

本文利用DataBinding的ViewDataBinding直接略去写ViewHolder。

利用Object类型的ItemPresenter,兼容解决了点击事件的设置。

最得意的设计,还是利用R.layout.xxxx这些布局文件int类型的的RID,作为ItemViewType,一箭双雕。

DataBinding很强,希望大家快点拥抱它。

to do listViewGroup Adapter 考虑加入复用缓存池

ViewGroup Adapter ,考虑替换onBindView()的ItemView->通用的ViewHolder,这样可以少写一些findViewById()代码

整合DataBinding 的通用Adapter入库。

完善 RecyclerView、ListView的通用Adapter,支持多种ItemViewType。

加入一些自定义ViewGroup入库,例如流式布局,九宫格,Banner轮播图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值