BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其一)

BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其三)

接上一章内容,如果大家没有看过第一章的话,请先看第一章。点上面链接就能跳转。

头部和脚部

public class HeadFootViewModel extends BaseBindingViewModel<SimpleData> {@Overrideprotected Map<Integer, CSBravhItemBinding> getItemBinding() {Map<Integer, CSBravhItemBinding> mp = new HashMap<>();mp.put(0, new CSBravhItemBinding(com.caesar.brvahbinding.BR.bean, R.layout.item_simple));return mp;}@Override//这个回调是头部的item的绑定数据,也支持绑定多个数据事件public ArrayList<CSBravhItemBinding> getHeadBinding() {ArrayList<CSBravhItemBinding> heads = new ArrayList<>();heads.add(new CSBravhItemBinding(BR.data, R.layout.layout_head_one, new HeadOneData(), BR.action, new brvah()));heads.add(new CSBravhItemBinding(BR.data, R.layout.layout_head_two, new HeadTwoData()));return heads;}@Override//这个回调是脚部的item的绑定数据,也支持绑定多个数据事件public ArrayList<CSBravhItemBinding> getFootBinding() {ArrayList<CSBravhItemBinding> foots = new ArrayList<>();foots.add(new CSBravhItemBinding(BR.data, R.layout.layout_foot_one, new FootOneData()));foots.add(new CSBravhItemBinding(BR.data, R.layout.layout_foot_two, new FootTwoData()));return foots;}@Overridepublic void load() {load(CreateData.getSimpleData());}@Overridepublic RecyclerView.ItemDecoration onitemDecoration() {return new NormalLineTopHeadDecoration(30, true);}//某个头部绑定的事件,告诉大家可以这样调用public class brvah implements CSAction0 {@Overridepublic void call() {bindingAdapter.removeAllHeaderView();}}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto">
。。。<androidx.recyclerview.widget.RecyclerViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:cs_brvah_Decoration="@{vm.itemDecoration}"app:cs_brvah_adapter="@{vm.bindingAdapter}"app:cs_brvah_footBinding="@{vm.footBinding}"app:cs_brvah_headBinding="@{vm.headBinding}" /></LinearLayout>
</layout>

先看布局文件,很简单,app:cs_brvah_footBinding="@{vm.footBinding}" app:cs_brvah_headBinding="@{vm.headBinding}"这2个方法,分别绑定了头部和脚部。接着,大家看HeadFootViewModel这个类,其中getHeadBinding()这个回调,是绑定头部的,跟普通的item绑定很像,只是少了个itemType,里面传布局跟data,也可以绑定其他的事件。同理脚部布局数据是getFootBinding()这个回调。是不是很简单。

空布局和下拉刷新

  <androidx.swiperefreshlayout.widget.SwipeRefreshLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"app:OnRefreshListener="@{vm.refreshListener}"app:refreshing="@{vm.isRefreshing}"><androidx.recyclerview.widget.RecyclerViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:cs_brvah_Decoration="@{vm.itemDecoration}"app:cs_brvah_adapter="@{vm.bindingAdapter}"app:cs_brvah_emptyClickListener="@{vm.emptyOnClickListener}"app:cs_brvah_emptyResId="@{vm.emptyResId}" /></androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
public class EmptyRefrshViewModel extends BaseBindingViewModel<SimpleData> {private int countD;@Overrideprotected Map<Integer, CSBravhItemBinding> getItemBinding() {Map<Integer, CSBravhItemBinding> mp = new HashMap<>();mp.put(0, new CSBravhItemBinding(com.caesar.brvahbinding.BR.bean, R.layout.item_simple));return mp;}@Override//里面模拟网络请求时,出现的情况,正常返回,数据为空,请求错误.public void load() {++countD;if (countD % 3 == 0) {load(CreateData.getSimpleData());} else if (countD % 3 == 1) {load(getEmptyData());} else if (countD % 3 == 2) {load(getErrorData());}}//模拟数据返回为空public static Flowable<List<SimpleData>> getEmptyData() {CSLog.Print("调用加载空布局");return Flowable.create(new FlowableOnSubscribe<List<SimpleData>>() {@Overridepublic void subscribe(FlowableEmitter<List<SimpleData>> emitter) throws Exception {ArrayList<SimpleData> data = new ArrayList<>();emitter.onNext(data);emitter.onComplete();}}, BackpressureStrategy.BUFFER).delay(3, TimeUnit.SECONDS);}//模拟网络请求出错public static Flowable<List<SimpleData>> getErrorData() {CSLog.Print("调用加载错误");return Flowable.create(new FlowableOnSubscribe<List<SimpleData>>() {@Overridepublic void subscribe(FlowableEmitter<List<SimpleData>> emitter) throws Exception {emitter.onError(null);}}, BackpressureStrategy.BUFFER).delay(1, TimeUnit.SECONDS);}//清空数据的点击事件,这边因为我的baseAdapter里面,对items做过监听,可以看CSBindingListChangedCallBack这个类,所以,当items的数据发生//改变时,绑定的适配器会自动刷新,所以,如果你是使用自己的适配器的话(下面会讲),别忘记刷新适配器public void cliear(View view) {items.clear();}@Overridepublic RecyclerView.ItemDecoration onitemDecoration() {return new NormalLineDecoration(30, true);}@Override//可以重写空布局的UIpublic int getEmptyViewRes(int type) {switch (type) {case EmptyViewType.ERROR:return R.layout.layout_frame_error_view;case EmptyViewType.LOADING:return R.layout.layout_frame_loading_view;case EmptyViewType.REFRESH:return R.layout.layout_frame_refresh_view;default:return R.layout.layout_frame_empty_view;}}
}

大家找到EmptyRefreshActivity这个界面,在布局文件中,我加了一个SwipeRefreshLayout下拉刷新控件,在里面,绑定了app:OnRefreshListener="@{vm.refreshListener}"和app:refreshing="@{vm.isRefreshing}",其中refreshListener这个是下拉监听器,我的baseViewModel中,写了监听回调,

//下拉刷新控件的监听器,里面调用重新加载数据的方法public SwipeRefreshLayout.OnRefreshListener getRefreshListener() {return new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {isRefreshing.set(true);reload();}};}

如果下拉了,就会调用重新加载的方法。而isRefreshing这个是刷新判断,因为跟下拉控件绑定在一起,所以下拉的时候,可以反应刷新控件的状态。然后在RecyclerView中,我绑定了app:cs_brvah_emptyClickListener="@{vm.emptyOnClickListener}" 和app:cs_brvah_emptyResId="@{vm.emptyResId}",第一个是绑定空布局的点击事件,下面是baseViewModel的部分相关代码

//空布局的点击事件,里面做判断,如果当前空布局不是正在加载的状态,点击之后,就重新获取数据protected View.OnClickListener getEmptyOnClickListener() {return new View.OnClickListener() {@Overridepublic void onClick(View v) {CSLog.Print("点击了空布局按钮");if (emptyResId.get() != getEmptyViewRes(EmptyViewType.LOADING)) {reload();emptyResId.set(getEmptyViewRes(EmptyViewType.LOADING));}}};}

当点击空布局时,如果当前不是正在加载的状态,就重新获取数据。

第二个vm.emptyResId是空布局的绑定,你可以在每个viewModel中,重写getEmptyViewRes这个方法,就可以定制空布局了。

侧滑删除和拖动

好,先来讲侧滑删除,大家找到SwipeActivity这个界面

public class SwipeViewModel extends BaseBindingViewModel<SimpleData> {private boolean isSwipe = true;。。。@Override//只要重写这个监听器,然后再布局中绑定,就能侧滑删除public OnItemSwipeListener getItemSwipeListener() {return new OnItemSwipeListener() {@Overridepublic void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int i) {}@Overridepublic void clearView(RecyclerView.ViewHolder viewHolder, int i) {}@Overridepublic void onItemSwiped(RecyclerView.ViewHolder viewHolder, int i) {}@Overridepublic void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float v, float v1, boolean b) {canvas.drawColor(ContextCompat.getColor(FramGroble.INSTANCE.getTopActivity(), R.color.colorAccent));}};}
//这边是一个控制侧滑开关的例子,通过获取Controller()来控制,我已经在适配器中封装好了public void onSwi(View view) {if (isSwipe) {isSwipe = false;bindingAdapter.getDraggableController().disableSwipeItem();} else {isSwipe = true;bindingAdapter.getDraggableController().enableSwipeItem();}}@Override//设置侧滑方向public int getOnSwipeMoveFrags() {return ItemTouchHelper.START | ItemTouchHelper.END;}
}
<androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_show"android:layout_width="match_parent"android:layout_height="match_parent"app:cs_brvah_SwipeMoveFrags="@{vm.swipeMoveFrags}"app:cs_brvah_Decoration="@{vm.itemDecoration}"app:cs_brvah_OnItemSwipeListener="@{vm.onItemSwipeListener}"app:cs_brvah_adapter="@{vm.bindingAdapter}"/>

是不是也很简单,首先看viewModel,只要你重写了OnItemSwipeListener这个监听回调,然后在布局文件中,将该监听器绑定在布局中,app:cs_brvah_OnItemSwipeListener="@{vm.onItemSwipeListener}"就可以了,是不是很简单。然后你还可以设置滑动的方向,默认是向后滑动删除的,你可以通过getOnSwipeMoveFrags()重写这个方法,进行设置,当然设置好了之后,别忘了在布局文件中去绑定。如果你想要设置滑动开关怎么办,那当然也是可以的,万能适配器通过一个Controller来进行控制,我已经封装在适配器里了,你可以通过bindingAdapter.getDraggableController()获取到,然后设置开关就可以,例子已经给出。

接下来是拖动功能

public class DragViewModel extends NonMultiViewModel {private boolean isSwipe = true;@Override//只要设置拖动监听器,就可以实现拖动功能public OnItemDragListener getItemDragListener() {return new OnItemDragListener() {@Overridepublic void onItemDragStart(RecyclerView.ViewHolder viewHolder, int i) {}@Overridepublic void onItemDragMoving(RecyclerView.ViewHolder viewHolder, int i, RecyclerView.ViewHolder viewHolder1, int i1) {}@Overridepublic void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int i) {}};}
//拖动开关public void onSwi(View view) {if (isSwipe) {isSwipe = false;bindingAdapter.getDraggableController().disableDragItem();} else {isSwipe = true;bindingAdapter.getDraggableController().enableDragItem(bindingAdapter.getItemTouchHelper(null));}}
}
<androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_show"android:layout_width="match_parent"android:layout_height="match_parent"app:cs_brvah_Decoration="@{vm.itemDecoration}"app:cs_brvah_OnItemDragListener="@{vm.onItemDragListener}"app:cs_brvah_adapter="@{vm.bindingAdapter}"app:cs_brvah_layoutManager="@{CSBrvahLayoutManager.grid(4)}"app:cs_brvah_multiType="@{vm.multiTypeDelegat}"app:cs_brvah_spansize="@{vm.spanSizeLookup}"/>

我这边拖动的viewModel,继承了另外一个NonMultiViewModel,因为界面是一样的。拖动跟侧滑很像,也只要重写getItemDragListener监听器就可以,然后在布局中,调用app:cs_brvah_OnItemDragListener="@{vm.onItemDragListener}"进行绑定。是不是超级简单。拖动的开关控制器,跟侧滑一样,也是调用getDraggableController(),不过打开拖动功能的时候,要注意bindingAdapter.getDraggableController().enableDragItem()里面要传一个Touch,这个touch要通过bindingAdapter.getItemTouchHelper(null)方法去获取,因为在绑定的时候,已经生成了一个touch,可以保证唯一性。例子里面都有。

我这边将拖动跟侧滑功能合在一起,做了个例子,大家可以找到DragASwipeActivity这个类,调用方法是一模一样的,我这里就不再重复了。

Expand可扩展的多布局

public class ExpandViewModel extends BaseBindingViewModel<MultiItemEntity> {。。。
//当每次数据加载完成的时候,都会回调该方法,我在这边,将列表展开@Overridepublic void onDataLoadComplete() {bindingAdapter.expandAll();}//模拟获取数据,这边的数据要继承AbstractExpandableItemprivate Flowable<List<MultiItemEntity>> getData() {return Flowable.create(new FlowableOnSubscribe<List<MultiItemEntity>>() {@Overridepublic void subscribe(FlowableEmitter<List<MultiItemEntity>> emitter) throws Exception {ArrayList<MultiItemEntity> data = new ArrayList<>();for (int i = 0; i < 5; i++) {ExDataGrandFa exDataGrandFa = new ExDataGrandFa("点我有惊喜", "点我啊", R.mipmap.headerandfooter_img1);for (int j = 0; j < 3; j++) {ExDataFather exDataFather = new ExDataFather("点我啊", "来点我啊", R.mipmap.m_img1);for (int k = 0; k < 6; k++) {ExDataChild exDataChild = new ExDataChild("点我消失", R.mipmap.head_img1);exDataFather.addSubItem(exDataChild);}exDataGrandFa.addSubItem(exDataFather);}data.add(exDataGrandFa);}emitter.onNext(data);emitter.onComplete();}}, BackpressureStrategy.BUFFER);}@Overridepublic RecyclerView.ItemDecoration onitemDecoration() {return new NormaltemDecoration(10);}//最外面item的点击事件,里面调用item的扩展和收缩.public class GrandAct implements CSAction1<ExDataGrandFa> {@Overridepublic void call(ExDataGrandFa param) {if (param.isExpanded()) {bindingAdapter.collapse(items.indexOf(param));} else {bindingAdapter.expand(items.indexOf(param));}}}//第二个item的点击事件,调用里面item的扩展和说收缩public class FatherAct implements CSAction1<ExDataFather> {@Overridepublic void call(ExDataFather param) {if (param.isExpanded()) {bindingAdapter.collapse(items.indexOf(param));} else {bindingAdapter.expand(items.indexOf(param));}}}//最里面item的点击事件,将item从本列表中删除,记住有2个地方要删除,一个是items,第二个是它外层的item中的数据public class ChildAct implements CSAction1<ExDataChild> {@Overridepublic void call(ExDataChild param) {//这一部分删除其实也不难,我是直接抄官方的,先获取当前item的父item,将集合中item去掉,再从父item中删掉当前item,要删2次int positionAtAll = getParentPositionInAll(items.indexOf(param));items.remove(param);if (positionAtAll != -1) {IExpandable multiItemEntity = (IExpandable) bindingAdapter.getData().get(positionAtAll);multiItemEntity.getSubItems().remove(param);}}}/*** 该方法用于 IExpandable 树形列表。* 如果不存在 Parent,则 return -1。** @param position 所处列表的位置* @return 父 position 在数据列表中的位置*/public int getParentPositionInAll(int position) {List<MultiItemEntity> data = bindingAdapter.getData();MultiItemEntity multiItemEntity = bindingAdapter.getItem(position);if (isExpandable(multiItemEntity)) {IExpandable IExpandable = (IExpandable) multiItemEntity;for (int i = position - 1; i >= 0; i--) {MultiItemEntity entity = data.get(i);if (isExpandable(entity) && IExpandable.getLevel() > ((IExpandable) entity).getLevel()) {return i;}}} else {for (int i = position - 1; i >= 0; i--) {MultiItemEntity entity = data.get(i);if (isExpandable(entity)) {return i;}}}return -1;}public boolean isExpandable(MultiItemEntity item) {return item != null && item instanceof IExpandable;}}

布局的代码没什么好说的,就是常规调用,来看一下viewModel,是不是跟普通的多布局很像,也是实现了MultiItemEntity,不同的地方就是,它的item要继承AbstractExpandableItem这个类,跟BRVAH中的一样,其中的action是我写的每个item的点击事件监听。也很简单。

下拉刷新,上拉加载

下拉上拉这一部分用的还是挺多的,所以我要稍微着重讲解一下,先贴代码

public abstract class LoadMoreBindingViewModel<B> extends BaseBindingViewModel<B> {//加载更多布局,可以自定义public LoadMoreView loadMoreView;//加载更多结束public ObservableBoolean loadMoreEnd;//是否能够加载更多public ObservableBoolean loadMoreEnable;//加载更多完成public ObservableBoolean loadMoreSuccess;//上拉加载的监听回调public BaseQuickAdapter.RequestLoadMoreListener loadMoreListener;//当前页数,默认从0开始,可以设置默认值public int mPage;//每页加载返回的个数,按照这个来判断是否已经加到头了public int PageSize = 15;//默认从第几页开始加载public int defaultStart;public LoadMoreBindingViewModel() {super();loadMoreView = getLoadMoreView();loadMoreListener = getLoadMoreListener();loadMoreEnd = new ObservableBoolean();loadMoreEnable = new ObservableBoolean();loadMoreSuccess = new ObservableBoolean();}protected LoadMoreView getLoadMoreView() {return new LoadMoreView() {@Overridepublic int getLayoutId() {return R.layout.view_load_more;}@Overrideprotected int getLoadingViewId() {return R.id.load_more_loading_view;}@Overrideprotected int getLoadFailViewId() {return R.id.load_more_load_fail_view;}@Overrideprotected int getLoadEndViewId() {return R.id.load_more_load_end_view;}};}protected BaseQuickAdapter.RequestLoadMoreListener getLoadMoreListener() {return new BaseQuickAdapter.RequestLoadMoreListener() {@Overridepublic void onLoadMoreRequested() {loadMore();}};}private void loadMore() {CSLog.Print("加载更多调用了");load();}@Overridepublic void load() {load(mPage);}@Overrideprotected void load(Flowable<List<B>> flowable) {if (isRefreshing.get()) {emptyResId.set(getEmptyViewRes(EmptyViewType.REFRESH));} else {CSLog.Print("调用了正在加载界面");emptyResId.set(getEmptyViewRes(EmptyViewType.LOADING));}disposable = flowable.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new Consumer<List<B>>() {@Overridepublic void accept(List<B> result) throws Exception {setData(result);}}, new Consumer<Throwable>() {@Overridepublic void accept(Throwable throwable) throws Exception {if (isRefreshing.get() || mPage == defaultStart) {emptyResId.set(getEmptyViewRes(EmptyViewType.ERROR));loadMoreEnable.set(true);} else {loadMoreSuccess.set(false);loadMoreSuccess.notifyChange();}isRefreshing.set(false);}}, new Action() {@Overridepublic void run() throws Exception {loadMoreEnable.set(true);emptyResId.set(getEmptyViewRes(EmptyViewType.EMPTY));isRefreshing.set(false);mPage++;}});}//重新加载,页数清空@Overridepublic void reload() {mPage = defaultStart;super.reload();}//设置默认从第几页开始加载public void setDefaultStart(int index) {defaultStart = index;mPage = index;}public void setData(List<B> dat) {addItems(dat);if (dat.size() < getPageSize()) {loadMoreEnd.set(mPage == defaultStart);loadMoreEnd.notifyChange();} else {loadMoreSuccess.set(true);loadMoreSuccess.notifyChange();}}public abstract void load(int mPage);public int getPageSize() {return PageSize;}public void setPageSize(int pageSize) {this.PageSize = pageSize;}
}
public class LoadMoreLineViewModel extends LoadMoreBindingViewModel<SimpleData> {private boolean isFirst = true;
//构造方法中,设置每页获取的个数,这个值是用来判断当前网络请求,是否是最后一页的数据public LoadMoreLineViewModel() {super();setPageSize(10);}@Overrideprotected Map<Integer, CSBravhItemBinding> getItemBinding() {Map<Integer, CSBravhItemBinding> mp = new HashMap<>();mp.put(0, new CSBravhItemBinding(com.caesar.brvahbinding.BR.bean, R.layout.item_simple));return mp;}
//模拟加载数据,模拟加载成功/失败和结束@Overridepublic void load(int mPage) {CSLog.Print("当前加载的页:" + mPage);if (mPage == 2) {if (isFirst) {isFirst = false;load(getErr());} else {load(getSimp());}} else if (mPage == 3) {load(getFsa());} else {load(getSimp());}}public Flowable<List<SimpleData>> getSimp() {return Flowable.create(new FlowableOnSubscribe<List<SimpleData>>() {@Overridepublic void subscribe(FlowableEmitter<List<SimpleData>> emitter) throws Exception {ArrayList<SimpleData> data = new ArrayList<>();data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img1));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img2));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img3));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img2));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img1));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img3));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img2));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img1));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img3));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img2));emitter.onNext(data);emitter.onComplete();}}, BackpressureStrategy.BUFFER).delay(3, TimeUnit.SECONDS);}public Flowable<List<SimpleData>> getErr() {return Flowable.create(new FlowableOnSubscribe<List<SimpleData>>() {@Overridepublic void subscribe(FlowableEmitter<List<SimpleData>> emitter) throws Exception {emitter.onError(null);}}, BackpressureStrategy.BUFFER).delay(3, TimeUnit.SECONDS);}public Flowable<List<SimpleData>> getFsa() {return Flowable.create(new FlowableOnSubscribe<List<SimpleData>>() {@Overridepublic void subscribe(FlowableEmitter<List<SimpleData>> emitter) throws Exception {ArrayList<SimpleData> data = new ArrayList<>();data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img1));data.add(new SimpleData("这货是个标题", "这货是个内容加描述", R.mipmap.animation_img2));emitter.onNext(data);emitter.onComplete();}}, BackpressureStrategy.BUFFER).delay(3, TimeUnit.SECONDS);}@Overridepublic RecyclerView.ItemDecoration onitemDecoration() {return new NormalLineDecoration(30, true);}}
 <androidx.swiperefreshlayout.widget.SwipeRefreshLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"app:OnRefreshListener="@{vm.refreshListener}"app:refreshing="@{vm.isRefreshing}"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_show"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="5dp"app:cs_brvah_Decoration="@{vm.itemDecoration}"app:cs_brvah_emptyResId="@{vm.emptyResId}"app:cs_brvah_emptyClickListener="@{vm.emptyOnClickListener}"app:cs_brvah_adapter="@{vm.bindingAdapter}"app:cs_brvah_loadMoreEnd="@{vm.loadMoreEnd}"app:cs_brvah_loadMoreEnable="@{vm.loadMoreEnable}"app:cs_brvah_loadMoreListener="@{vm.loadMoreListener}"app:cs_brvah_loadMoreSuccess="@{vm.loadMoreSuccess}"app:cs_brvah_loadMoreView="@{vm.loadMoreView}"/></androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

好,大家先找到LoadMoreLineActivity界面,仔细的同学就会发现,这边的viewModel我继承的是LoadMoreBindingViewModel,而LoadMoreBindingViewModel又是继承BaseBindingViewModel。

我们先看LoadMoreBindingViewModel,里面,新增加了一些属性,有LoadMoreView loadMoreView,这个是上拉加载的动画,可以用户自己定制,只要重写getLoadMoreView方法就可以了。bservableBoolean loadMoreEnd这个是判断是否已经加载结束。其中最关键的是新增的属性mPage,加载更多是有页数的,所以mPage这个值,就表示当前加载的是第几页,默认0,也可以设置从第1页开始加载。PageSize这个属性是判断是否已经加载到尾部,如果你加载回来的个数,小于这个值,就表示已经加载到头了。defaultStart这个值,是判断初始是从第几页开始加载。

好,接下来我们来看看LoadMoreLineViewModel这个类,其实也简单,就是一些常规的调用,不过原先重写的load()回调中,里面加了一个int mpage参数,这个就是当前加载的页数。然后数据请求加载的方式,跟原先的是一样的。

最后来看一下布局文件的代码。下拉刷新控件的绑定我上面已经讲过了,这边就不讲了,主要是列表的绑定,如果你是想要你的布局支持加载更多的话,其中,app:cs_brvah_loadMoreEnd="@{vm.loadMoreEnd}" app:cs_brvah_loadMoreEnable="@{vm.loadMoreEnable}" app:cs_brvah_loadMoreListener="@{vm.loadMoreListener}" app:cs_brvah_loadMoreSuccess="@{vm.loadMoreSuccess}"app:cs_brvah_loadMoreView="@{vm.loadMoreView}"

是必须要加的,判断加载状态,加载监听,加载时的动画等等,直接照写就完事。

  @BindingAdapter(value = {"cs_brvah_loadMoreEnd"})public static void onLoadMoreEnd(RecyclerView recyclerView, ObservableBoolean loadMoreEnd) {CSLog.Print("加载结束调用:" + loadMoreEnd.get());RecyclerView.Adapter adapter = recyclerView.getAdapter();if (adapter instanceof BaseQuickAdapter) {CSLog.Print("进入加载结束调用:" + loadMoreEnd.get());((BaseQuickAdapter) adapter).loadMoreEnd(loadMoreEnd.get());}}@BindingAdapter(value = {"cs_brvah_loadMoreEnable"})public static void onLoadMoreEnable(RecyclerView recyclerView, ObservableBoolean loadMoreEnable) {CSLog.Print("是否加载更多:" + loadMoreEnable.get());RecyclerView.Adapter adapter = recyclerView.getAdapter();if (adapter instanceof BaseQuickAdapter) {CSLog.Print("进入是否加载更多:" + loadMoreEnable.get());((BaseQuickAdapter) adapter).setEnableLoadMore(loadMoreEnable.get());}}@BindingAdapter(value = {"cs_brvah_loadMoreSuccess"})public static void onLoadMoreSuccess(RecyclerView recyclerView, ObservableBoolean loadMoreSuccess) {CSLog.Print("是否加载成功:" + loadMoreSuccess.get());RecyclerView.Adapter adapter = recyclerView.getAdapter();if (adapter instanceof BaseQuickAdapter) {CSLog.Print("进入是否加载成功:" + loadMoreSuccess.get());if (loadMoreSuccess.get()) {((BaseQuickAdapter) adapter).loadMoreComplete();} else {((BaseQuickAdapter) adapter).loadMoreFail();}}}@BindingAdapter(value = {"cs_brvah_emptyResId", "cs_brvah_emptyClickListener"})public static void onEmptyView(RecyclerView recyclerView, ObservableInt emptyResId, View.OnClickListener clickListener) {CSLog.Print("加载空布局调用");RecyclerView.Adapter adapter = recyclerView.getAdapter();if (adapter instanceof BaseQuickAdapter) {if (emptyResId != null) {CSLog.Print("进入加载空布局");((BaseQuickAdapter) adapter).setEmptyView(emptyResId.get(), (ViewGroup) recyclerView.getParent());}if (clickListener != null && ((BaseQuickAdapter) adapter).getEmptyView() != null) {CSLog.Print("进入加载空布局监听事件");((BaseQuickAdapter) adapter).getEmptyView().setOnClickListener(clickListener);}}}

上面这些是CSBrvahBindingAdapter中,databinding绑定的代码。其实归根到底,还是调用了BRVAH的方法。

哇,又写了这么多了,那再起一页吧。

BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其一)

BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其三)

BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(二)相关推荐

  1. BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(一)

    BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其二) BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其三 ...

  2. BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(三)

    BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其一) BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其二 ...

  3. mvvm模式和mvc的区别_Android 开发中的架构模式 -- MVC / MVP / MVVM

    预备知识 了解 Android 基本开发 看完本文可以达到什么程度 了解如何分析一个架构模式 掌握 MVC,MVP,MVVM 架构定义和实现 更多面试内容,面试专题,flutter视频 全套,音视频从 ...

  4. c# mvvm模式获取当前窗口_对Vue中的MVVM原理解析和实现

    首先你对Vue需要有一定的了解,知道MVVM.这样才能更有助于你顺利的完成下面原理的阅读学习和编写 下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家可以学习到: 1.Vue数据双向 ...

  5. WPF中Mvvm模式的理解

    1. Mvvm是什么,Mvvm是怎么来的? Mvvm模式广泛应用在WPF项目开发中,使用此模式可以把UI和业务逻辑分离开,使UI设计人员和业务逻辑人员能够分工明确. Mvvm模式是根据MVP模式来的, ...

  6. [Silverlight]使用MVVM模式打造英汉词典

    最近比较关注MVVM(Model-View_ViewModel)模式,该模式十分适合WPF/Silverlight的开发.出于练习的目的打算使用Silverlight做个英汉词典(可能是由于近来疯狂的 ...

  7. mvvm模式和mvc的区别_被误解的 MVC 和被神化的 MVVM,值得收藏!

    MVC 的历史 MVC,全称是 Model View Controller,是模型 (model)-视图 (view)-控制器 (controller) 的缩写.它表示的是一种常见的客户端软件开发框架 ...

  8. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  9. Android MVC,MVP,MVVM模式入门——重构登陆注册功能

    一  MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): ...

最新文章

  1. 初识聚类算法:K均值、凝聚层次聚类和DBSCAN 转载的聚类总结
  2. boost::core::bit_cast的测试程序
  3. ws配置 zuul_SpringCloud系列研究---服务网关zuul
  4. .Net 如何模拟会话级别的信号量,对http接口调用频率进行限制(有demo)
  5. 2019-03-22-算法-进化(回文链表)
  6. matlab约当消去法,Gauss消去法解线性方程组(Matlab)
  7. 环境配置与PyG中图与图数据集的使用
  8. Python webdriver调用Chrome报错
  9. Transformers与图神经网络的关系,我们能从transformer学习到什么?
  10. win7开放80端口
  11. 大数据分析平台有哪些功能
  12. PCL Save VTK File With Texture Coordinates 使用PCL库来保存带纹理坐标的VTK文件
  13. html5 侧面板展开折叠,css实现侧边展开收起
  14. Codeforces 741D dsu on tree
  15. 怎样在微信公众平台上传文件给别人下载
  16. Ubuntu下deb包的安装方法
  17. Android DLNA投屏-基本原理
  18. 对称加密,非对称加密详解
  19. android的json数据解析,Android数据解析-JSON解析
  20. 代数合并同类项计算机步骤,代数式(合并同类项)

热门文章

  1. 叶黄素的17种功效与副作用(5点使用禁忌请小心)
  2. 吃瓜群众从来不在意枪击案是不是因为代码规范引发的
  3. Noise2Void 的一些学习总结
  4. 凭栏听音,化险为夷——配电系统中的电磁隐患解析
  5. 抓包和网络镜像 华为交换机S2300
  6. ansys与solidworks关联失败_SolidWorks与ANSYS之间的数据交换方法研究
  7. history 清空历史记录 或 history不记录历史命令
  8. 菜鸟要飞系列目录(在更)
  9. make menuconfig缺少ncurses
  10. SQL触发器实例(下)