databinding 自定义view中的双向绑定
需求场景 :
在viewmodel中需要改变一个自定义view的自定义属性(比如 smartrefashlayout的下拉刷新去请求数据,以及加载完成或者刷新完成关闭加载动画)
思路:
1.mvvmlight 提供的command 方式(只适合自定义view中存在暴露给外部监听的方式,或者自
己通过bindadapter监听某个状态达到目的的场景,后面会讲具体实现)
command 的解决问题的方式是利用了bindadapter 和 java8的函数式编程(当然你用rxjava
也ok)。
2.通过bindadapter 和 InverseBindingAdapter (https://www.jianshu.com/p/a05c9735f595)/(https://yq.aliyun.com/articles/615840)
方式1 实现步骤:
a. 定义command (jdk8的函数接口)
@FunctionalInterface
public interface ReplyCommand {
void exectue();
}
b.BindingAdapter
public class BindingAdapters {
@BindingAdapter({"onRefreshCommand"})
public static void setonRefreshCommand(SmartRefreshLayout smartRefreshLayout, final ReplyCommand onRefreshCommand) {
smartRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(RefreshLayout refreshLayout) {
onRefreshCommand.exectue();
}
});
}
@BindingAdapter({"onloadmoreCommand"})
public static void setonloadmoreCommand(SmartRefreshLayout smartRefreshLayout, final ReplyCommand onloadmoreCommand) {
smartRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(RefreshLayout refreshLayout) {
onloadmoreCommand.exectue();
}
});
}
@BindingAdapter({"oncompleteCommand"})
public static void setoncompleteCommand(SmartRefreshLayout smartRefreshLayout, final ReplyCommandParam oncompleteCommand) {
oncompleteCommand.exectue(smartRefreshLayout);
}
}
c. xml 中引用
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:onRefreshCommand="@{viewModel.onrefreshCommand}"
bind:onloadmoreCommand="@{viewModel.onloadmoreCommand}">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:itemView="@{viewModel.KnowitemBinding}"
bind:items="@{viewModel.knowItems}"
bind:layoutManager="@{LayoutManager.linear()}" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
d.viewmodel 中使用
public final ReplyCommand onrefreshCommand = ()->{ getKnowledgeHierarchyData();};
public final ReplyCommand onloadmoreCommand = ()->{ getKnowledgeHierarchyData();};
结果: 发现下拉刷新丝滑了,数据驱动,但是你会发现数据获取成功后加载的动画并没有关闭 so 方式二就需要出场救急了
方式二实现步骤
1. 下载smartrefashlayout 的源码,使用导入module的方式引入项目(因为对反向绑定的InverseBindingMethods使用的不多,接下来会研究,等第二篇)
-
增加view的自定义属性 <attr name="refreshcomplete" format="boolean"/> 3. initview的时候获取属性并提供setter getter,
refreshcomplete =
ta.getBoolean(R.styleable.SmartRefreshLayout_refreshcomplete,false);public boolean getRefreshcomplete() { return refreshcomplete; } public void setRefreshcomplete(boolean refreshcomplete) { this.refreshcomplete = refreshcomplete; }
- 自己领会下,等后边步骤看完就知道为嘛要这样了
@BindingAdapter("refreshcompleteAttrChanged")
public static void setRefreshcompleteAttrChanged(SmartRefreshLayout view, InverseBindingListener inverseBindingListener) {
if (inverseBindingListener == null) {
view.setListener(null);
} else {
view.setListener(inverseBindingListener::onChange);
}
}
@BindingAdapter(value = "refreshcomplete")
public static void setcomplete(SmartRefreshLayout view, boolean refreshcomplete) {
view.setRefreshcomplete(refreshcomplete);
if(refreshcomplete){
view.finishRefresh();
view.finishLoadMore();
}
}
@InverseBindingAdapter(attribute = "refreshcomplete", event = "refreshcompleteAttrChanged")
public static boolean getcomplete(SmartRefreshLayout view) {
return view.getRefreshcomplete();
}
private OnValueChangedListener listener;
public interface OnValueChangedListener {
void onValueChanged();
}public void setListener(OnValueChangedListener listener) {
this.listener = listener;
}- 定义 实体类,xml中使用
public class Testvo extends BaseObservable implements Serializable {
- 自己领会下,等后边步骤看完就知道为嘛要这样了
public boolean complete;
@Bindable
public boolean getComplete() {
return complete;
}
public void setComplete(boolean complete) {
this.complete = complete;
notifyPropertyChanged(BR.complete);
}
}
注意规范,类的首字母必须大写,书写规范能避免很多大坑
<variable
name="data"
type="com.docker.moduleplayer.vo.Testvo"/>
<import type="com.docker.commonlibrary.bind.recycleviewbind.LayoutManager" />
</data>
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:refreshcomplete="@={data.complete}"
bind:onRefreshCommand="@{viewModel.onrefreshCommand}"
bind:onloadmoreCommand="@{viewModel.onloadmoreCommand}">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:itemView="@{viewModel.KnowitemBinding}"
bind:items="@{viewModel.knowItems}"
bind:layoutManager="@{LayoutManager.linear()}" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
- viewmodel 中实例化
public Testvo vo = new Testvo();
activity 中setData
7.完成,再回头看步骤4,有没有明白呢?