BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(二)
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中快捷、方便地使用(二)相关推荐
- BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(一)
BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其二) BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其三 ...
- BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合,Recyclerview如何在Databinding中快捷、方便地使用(三)
BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其一) BRVAH的BaseRecyclerViewAdapterHelper与MVVM模式优雅结合(其二 ...
- mvvm模式和mvc的区别_Android 开发中的架构模式 -- MVC / MVP / MVVM
预备知识 了解 Android 基本开发 看完本文可以达到什么程度 了解如何分析一个架构模式 掌握 MVC,MVP,MVVM 架构定义和实现 更多面试内容,面试专题,flutter视频 全套,音视频从 ...
- c# mvvm模式获取当前窗口_对Vue中的MVVM原理解析和实现
首先你对Vue需要有一定的了解,知道MVVM.这样才能更有助于你顺利的完成下面原理的阅读学习和编写 下面由我阿巴阿巴的详细走一遍Vue中MVVM原理的实现,这篇文章大家可以学习到: 1.Vue数据双向 ...
- WPF中Mvvm模式的理解
1. Mvvm是什么,Mvvm是怎么来的? Mvvm模式广泛应用在WPF项目开发中,使用此模式可以把UI和业务逻辑分离开,使UI设计人员和业务逻辑人员能够分工明确. Mvvm模式是根据MVP模式来的, ...
- [Silverlight]使用MVVM模式打造英汉词典
最近比较关注MVVM(Model-View_ViewModel)模式,该模式十分适合WPF/Silverlight的开发.出于练习的目的打算使用Silverlight做个英汉词典(可能是由于近来疯狂的 ...
- mvvm模式和mvc的区别_被误解的 MVC 和被神化的 MVVM,值得收藏!
MVC 的历史 MVC,全称是 Model View Controller,是模型 (model)-视图 (view)-控制器 (controller) 的缩写.它表示的是一种常见的客户端软件开发框架 ...
- js架构设计模式——由项目浅谈JS中MVVM模式
1. 背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...
- Android MVC,MVP,MVVM模式入门——重构登陆注册功能
一 MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): ...
最新文章
- 初识聚类算法:K均值、凝聚层次聚类和DBSCAN 转载的聚类总结
- boost::core::bit_cast的测试程序
- ws配置 zuul_SpringCloud系列研究---服务网关zuul
- .Net 如何模拟会话级别的信号量,对http接口调用频率进行限制(有demo)
- 2019-03-22-算法-进化(回文链表)
- matlab约当消去法,Gauss消去法解线性方程组(Matlab)
- 环境配置与PyG中图与图数据集的使用
- Python webdriver调用Chrome报错
- Transformers与图神经网络的关系,我们能从transformer学习到什么?
- win7开放80端口
- 大数据分析平台有哪些功能
- PCL Save VTK File With Texture Coordinates 使用PCL库来保存带纹理坐标的VTK文件
- html5 侧面板展开折叠,css实现侧边展开收起
- Codeforces 741D dsu on tree
- 怎样在微信公众平台上传文件给别人下载
- Ubuntu下deb包的安装方法
- Android DLNA投屏-基本原理
- 对称加密,非对称加密详解
- android的json数据解析,Android数据解析-JSON解析
- 代数合并同类项计算机步骤,代数式(合并同类项)