如何为 material.Slider 视图创建绑定适配器?
How to create Binding Adapter for material.Slider view?
我的目标是将 material.Slider 视图从我的视图模型双向数据绑定到 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 的正确属性 class?
让我们看看SeekBarBindingAdapter'ssetOnSeekBarChangeListener()
方法。它添加了四个不同的属性:{"android:onStartTrackingTouch", "android:onStopTrackingTouch", "android:onProgressChanged", "android:progressAttrChanged"}
但只有最后一个属性被双向数据绑定使用。
但是为什么有四个属性呢?如果您查看 SeekBar class, it has setOnSeekBarChangeListener()
method which allows you to set and remove a listener. The problem is that SeekBar can only have one listener, and that listener 提供不同的回调:onProgressChanged
、onStartTrackingTouch
和 onStopTrackingTouch
。
SeekBarBindingAdapter
注册自己的监听器,这意味着没有人可以在不删除现有监听器的情况下注册另一个监听器。这就是 SeekBarBindingAdapter
提供 onStartTrackingTouch
、onStopTrackingTouch
和 onProgressChanged
属性的原因,这样您就可以在不注册自己的 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()
}
}
布局:
...
<com.google.android.material.slider.Slider
...
android:value="@={model.count}" />
...
您可以找到完整的资源 here。
我的目标是将 material.Slider 视图从我的视图模型双向数据绑定到 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
但如果我只使用
为什么它会查找 valueAttrChangedandroid:value="@={viewmodel.fps}"
?
如果我在 Slider 中看不到 valueAttrChanged,如何找到要添加到 BindingAdapter 的正确属性 class?
让我们看看SeekBarBindingAdapter'ssetOnSeekBarChangeListener()
方法。它添加了四个不同的属性:{"android:onStartTrackingTouch", "android:onStopTrackingTouch", "android:onProgressChanged", "android:progressAttrChanged"}
但只有最后一个属性被双向数据绑定使用。
但是为什么有四个属性呢?如果您查看 SeekBar class, it has setOnSeekBarChangeListener()
method which allows you to set and remove a listener. The problem is that SeekBar can only have one listener, and that listener 提供不同的回调:onProgressChanged
、onStartTrackingTouch
和 onStopTrackingTouch
。
SeekBarBindingAdapter
注册自己的监听器,这意味着没有人可以在不删除现有监听器的情况下注册另一个监听器。这就是 SeekBarBindingAdapter
提供 onStartTrackingTouch
、onStopTrackingTouch
和 onProgressChanged
属性的原因,这样您就可以在不注册自己的 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()
}
}
布局:
...
<com.google.android.material.slider.Slider
...
android:value="@={model.count}" />
...
您可以找到完整的资源 here。