【问题标题】:BindingAdapter with lamba as argument以lamba为参数的BindingAdapter
【发布时间】:2018-04-24 10:49:34
【问题描述】:

使用 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);
    }
  });
}

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

【问题讨论】:

    标签: java android data-binding android-databinding


    【解决方案1】:

    由于您希望它像内置的 onClick 一样工作,我们来看看 official binding adapter 的 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 属性的内置绑定适配器,但我想这只是一个示例,您实际上想学习如何制作自定义适配器。但请注意不要选择框架中已经存在的属性名称,以免发生冲突。

    【讨论】:

    • 它对我不起作用:{"msg":"处理布局文件时出现意外错误:
    【解决方案2】:

    如果 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 警告

    【讨论】:

      【解决方案3】:

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

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

      在您的视图模型中。

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

      【讨论】:

        猜你喜欢
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-03
        • 2017-03-16
        • 2019-11-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多