BindingAdapter与lamba作为参数

时间:2018-04-24 10:49:34

标签: java android data-binding android-databinding

使用Android数据绑定,我可以执行以下操作:

<View
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:onClick="@{() -> viewModel.onClick()}" />

我的ViewModel不必实施OnClickListener,只是有一个方法:

public void onClick() {

}

它传递给Xml中的onClick属性对我来说就像一个lambda。

我如何使用自己的BindingAdapters

执行此操作

我想要的是什么: 让我们假设我想绑定触摸事件,我想传递MotionEvent,我想这会像这样看一下Xml:

<View
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:onTouch="(view, event) -> viewModel.onTouch(event)" />

BindingAdapter类似:

@BindingAdapter("onTouch")
public static void onTouch(View view, ??? lambda) {
  view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
      return lambda(event);
    }
  });
}

希望我的ViewModel实现OnTouchListener并将其绑定为:

@BindingAdapter()
public  static  void onTouch(View view, View.OnTouchListener onTouchListener) {
    view.setOnTouchListener(onTouchListener);
}

而我希望将触摸事件直接绑定到我的ViewModel,如:

@BindingAdapter()
public static void onTouch(final View view, final MyViewModel myViewModel) {
  view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(final View v, final MotionEvent event) {
      return myViewModel.onTouch(view, myViewModel);
    }
  });
}

这是否可以通过数据绑定实现?

3 个答案:

答案 0 :(得分:2)

您希望它像内置的onClick一样工作,让我们看一下official binding adapter for onClick属性:

@BindingAdapter({"android:onClick", "android:clickable"})
public static void setOnClick(View view, View.OnClickListener clickListener, boolean clickable) {
    view.setOnClickListener(clickListener);
    view.setClickable(clickable);
}

如您所见,绑定适配器不使用lambda作为参数,而是使用侦听器。但是您可以在xml中将lambda传递给它(因为它是单个方法接口)

这是您需要的绑定适配器:(我选择了另一个属性名称,因为框架已经使用了onTouch)

@BindingAdapter("onImageTouch")
public static void onImageTouch(View view, View.OnTouchListener onTouchListener) {
    view.setOnTouchListener(onTouchListener);
}

这是在xml中使用它的方式:

app:onImageTouch="@{(view, event) -> viewModel.onImageTouch(event)}"

这是viewmodel中的相应方法:

public boolean onImageTouch(MotionEvent event){
    Timber.e("OnImageTouch is called");
    return true;
}

(它什么也不做,但是请注意它应该返回一个布尔值,因为onTouch回调返回一个布尔值。)

您不需要在视图模型或活动中实现OnTouchListener。这与开始时使用onClick的示例非常相似。

让我注意到,已经有一个内置的onTouch属性绑定适配器,但是我想那只是一个例子,实际上您想学习如何制作自定义的适配器。但是请注意不要选择框架中已经存在的属性名称,以免发生冲突。

答案 1 :(得分:0)

可以将数据传递给视图模型,但是您还必须将视图与数据一起传递。所以在你的情况下。你需要做的是如下。

<View
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:onClick="@{() -> viewModel.onClick(view.someData)}" />

在你的视图模型中。

public void onClick(View v,String someData) {
}

答案 2 :(得分:0)

如果lambda返回boolean,则可以使用自己的方法,并使用属性app:onTouchListener。无需自定义BindingAdapter

<View
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:onTouchListener="(view, event) -> viewModel.onTouch(event)" />

android:onTouch也有效,但您会收到Unknown attribute lint警告

相关问题