11

我的目标是 2 路数据绑定材料。从我的视图模型到 MutableLiveData 的滑块视图:

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

当然,它不起作用,因为 androidx.databinding 库中没有 Slider 的数据绑定适配器

[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

据我了解,2 向数据绑定应该只适用于“progress”属性,而 1 向数据绑定需要两个属性:“onChanged”和“progress”

我尝试为 Slider 调整 SeekBarBindingAdapter:

    @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

但是如果我只使用它为什么会寻找 valueAttrChanged

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

?

如果在 Slider 类中看不到 valueAttrChanged,如何找到要添加到 BindingAdapter 的正确属性?

4

1 回答 1

7

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

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

SeekBarBindingAdapter注册自己的监听器,这意味着没有人可以在不删除现有监听器的情况下注册另一个监听器。这就是SeekBarBindingAdapter提供onStartTrackingTouch,onStopTrackingTouchonProgressChanged属性的原因,因此您可以在不注册自己的OnSeekBarChangeListener.

实际上,Slider适配器可以比 简单得多SeekBarBindingAdapter,因为 Slider 允许您使用addOnChangeListener()and添加和删除侦听器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()
    }
}

和布局:

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

您可以在此处找到完整的资源。

于 2020-05-31T15:04:59.690 回答