以 lamba 作为参数的 BindingAdapter
BindingAdapter with lamba as argument
使用 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);
}
});
}
数据绑定是否可行?
可以将数据传递给您的视图模型,但是您还必须将视图与数据一起传递。所以在你的情况下。您需要做的如下。
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.onClick(view.someData)}" />
并在您的视图模型中。
public void onClick(View v,String someData) {
}
如果 lambda returns a 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 警告
既然你希望它像内置的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;
}
(它什么都不做,但请注意它应该 return 一个布尔值,因为 onTouch 回调 return 是一个布尔值。)
您不需要在视图模型或 activity 中实现 OnTouchListener。这与您一开始给出的 onClick 示例非常相似。
请注意,已经有一个用于 onTouch 属性的内置绑定适配器,但我想这只是一个示例,您实际上想学习如何制作自定义适配器。但注意不要选择框架中已经存在的属性名称,以免发生冲突。
使用 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);
}
});
}
数据绑定是否可行?
可以将数据传递给您的视图模型,但是您还必须将视图与数据一起传递。所以在你的情况下。您需要做的如下。
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> viewModel.onClick(view.someData)}" />
并在您的视图模型中。
public void onClick(View v,String someData) {
}
如果 lambda returns a 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 警告
既然你希望它像内置的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;
}
(它什么都不做,但请注意它应该 return 一个布尔值,因为 onTouch 回调 return 是一个布尔值。)
您不需要在视图模型或 activity 中实现 OnTouchListener。这与您一开始给出的 onClick 示例非常相似。
请注意,已经有一个用于 onTouch 属性的内置绑定适配器,但我想这只是一个示例,您实际上想学习如何制作自定义适配器。但注意不要选择框架中已经存在的属性名称,以免发生冲突。