我的目标是双向数据绑定material .从我的viewmodel滑动到可变LiveData的视图:

   <com.google.android.material.slider.Slider
        ...
        android:value="@={viewmodel.fps}"
        ...
    />

Of course, it's not working because there is no databinding adapter for Slider in androidx.databinding library

[databinding] Cannot find a getter for <com.google.android.material.slider.Slider android:value> that accepts parameter type <java.lang.Integer>. If a binding adapter provides the getter, check that the adapter is annotated correctly and that the parameter type matches.

但是,他们有一个SeekBar:/androidx/databinding/adapters/SeekBarBindingAdapter.java

据我所知,双向数据绑定应该只使用"progress"属性,而单向数据绑定需要两个属性:"onChanged"和"progress"

我try 将SeekBarBindingAdapter改编为Slider:

    @InverseBindingMethods({
            @InverseBindingMethod(type = Slider.class, attribute = "android:value"),
    })
    public class SliderBindingAdapter {
        @BindingAdapter("android:value")
        public static void setValue(Slider view, int value) {
            if (value != view.getValue()) {
                view.setValue(value);
            }
        }

@BindingAdapter(value = {"android:valueAttrChanged", "android:onValueChange"}, requireAll = false)
    public static void setOnSliderChangeListener(Slider view, final Slider.OnChangeListener valChanged, final InverseBindingListener attrChanged) {
        if (valChanged == null)
            view.addOnChangeListener(null);
        else
            view.addOnChangeListener((slider, value, fromUser) -> {
                if (valChanged != null)
                    valChanged.onValueChange(slider, value, fromUser);
            });


        if (attrChanged != null) {
            attrChanged.onChange();
        }
    }

    @Override
    public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {

    }

这不是建筑:

Could not find event android:valueAttrChanged on View type Slider

但是为什么它要查找value如果我只使用

android:value="@={viewmodel.fps}"

How do I find the right attribute to add to BindingAdapter, if I don't see valueAttrChanged in Slider class?

推荐答案

让我们看一下SeekBarBindingAdapter'ssetOnSeekBarChangeListener()方法.它添加了四个不同的属性:{"android:onStartTrackingTouch", "android:onStopTrackingTouch", "android:onProgressChanged", "android:progressAttrChanged"},但只有最后一个用于双向数据绑定.

但是为什么有四个属性呢?如果您查看SeekBar个类,它有setOnSeekBarChangeListener()个方法,允许您设置和删除侦听器.问题是SeekBar只能有一个监听器,而listener提供不同的回调:onProgressChangedonStartTrackingTouchonStopTrackingTouch.

SeekBarBindingAdapter注册自己的监听器,这意味着如果不删除现有的监听器,任何人都不能注册另一个监听器.这就是为什么SeekBarBindingAdapter提供了onStartTrackingTouchonStopTrackingTouchonProgressChanged个属性,所以你可以在不注册自己的OnSeekBarChangeListener的情况下收听这些事件.

实际上,Slider适配器可能比SeekBarBindingAdapter简单得多,因为Slider允许您使用addOnChangeListener()removeOnChangeListener()添加和删除侦听器.因此,双向数据绑定适配器可以注册自己的侦听器,其他任何人都可以注册其他侦听器,而无需删除以前的侦听器.

它允许我们定义一个非常简洁的适配器.我创建了一个kotlin示例,希望您能将其翻译成java:

@InverseBindingAdapter(attribute = "android:value")
fun getSliderValue(slider: Slider) = slider.value

@BindingAdapter("android:valueAttrChanged")
fun setSliderListeners(slider: Slider, attrChange: InverseBindingListener) {
    slider.addOnChangeListener { _, _, _ ->
        attrChange.onChange()
    }
}

And the layout:

...
<com.google.android.material.slider.Slider
    ...
    android:value="@={model.count}" />
...

You can find the full sources here.

Kotlin相关问答推荐

当通过firstOrders访问时,存储在伴随对象中的对象列表具有空值

Kotlin-删除按钮周围的空格

Android Jetpack编写androidx.compose.oundation.lazy.grid.Items

处理合成层次 struct 中的深层按钮以切换视图

扩展属性委托给实例属性

如何使用 Firebase 和 Kotlin 在文本 (Jetpack Compose) 中显示当前用户名?

Kotlin 使用委托进行隐式覆盖

在 kotlin 中重载函数时,我在一些非常基本的代码上不断收到类型不匹配

是什么让 Kotlin 中的 String 类能够使用方括号?

Kotlin 日期格式从一种更改为另一种

异常传播如何在 CoroutineScope.async 上工作?

为什么 android studio 不为所有安全参数生成代码?

将 Kotlin 类属性设置器作为函数引用

在粘贴时将 java 转换为 kotlin

Android Studio 将 Java 转换为 Kotlin 错误无法推断此参数的类型

Kotlin 中的内联构造函数是什么?

Kapt不适用于Android Studio 3.0中的AutoValue

Java Integer.MAX_VALUE 与 Kotlin Int.MAX_VALUE

在 intelliJ 元素中集成 Kotlinx 协程

Kotlin反射不可用