databinding 自定义view中的双向绑定

2019-03-13  本文已影响0人  Lz_Docker

需求场景 :
在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使用的不多,接下来会研究,等第二篇)
  1. 增加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;
         }
    
    1. 自己领会下,等后边步骤看完就知道为嘛要这样了
      @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;
    }

    1. 定义 实体类,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>
  1. viewmodel 中实例化
    public Testvo vo = new Testvo();
    activity 中setData

7.完成,再回头看步骤4,有没有明白呢?

上一篇下一篇

猜你喜欢

热点阅读