android 数据绑定:如何避免以编程方式触发 onCheckedChanged

android databinding: how to avoid onCheckedChanged triggered by programmatically

我现在正在尝试在我的项目中使用android数据绑定,遇到这种问题,例如:我有3个复选框作为一个复选框组,如果第一个复选框被选中,那么一个变量 type 为 1。第二个使 type 变为 2,第三个使 type 变为 3。所以我以这种方式实现代码。

   // layout.xml


   <android.support.v7.widget.AppCompatCheckBox
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:checked="@{userInfoViewModel.type == 1}"
        android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 1)}"
        />

   <android.support.v7.widget.AppCompatCheckBox
        android:layout_width="50dp"
        android:layout_height="55dp"
        android:checked="@{userInfoViewModel.type == 2}"
        android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 2)}"
        />

    <android.support.v7.widget.AppCompatCheckBox
        android:layout_width="50dp"
        android:layout_height="55dp"
        android:checked="@{userInfoViewModel.type == 3}"
        android:onCheckedChanged="@{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 3)}"
        />

// viewModel

public void onTypeChecked(boolean checked, int i) {
    if (checked) {
        // if it is a check. set the type
        type.set(i);
    } else {
        // if it is a uncheck. set type to unknown
        type.set(0);
    }
}

现在的问题是,如果我选中了第一个复选框,那么我会选中第二个。 type 应设置为 2,并且 UI 应正确更新。但实际情况是uncheck事件也发生在第一个checkbox上,type设置为2后,然后触发type.set(0),所以没有checkbox被选中。

其实这个问题和onCheckedChanged called automatically是一样的。我需要的是数据绑定的解决方案。

在非数据绑定项目中,我认为最好的解决方案是使用 setCheckedSilent(@Emanuel Andrada 的回答)。

  public void setCheckedSilent(boolean checked) {
    super.setOnCheckedChangeListener(null);
    super.setChecked(checked);
    super.setOnCheckedChangeListener(listener);
}

但是在数据绑定中,我不能这样做。那么有没有高手可以帮帮我呢?

根据@Arpan Sharma 的回答,听 onClick 而不是 onCheckedChanged。此解决方案目前有效,但我担心 checked 的值,它总是正确的吗?

public void onTypeChecked(View view, int i) {
    Boolean checked = ((CheckBox) view).isChecked();

    if (checked) {
        type.set(i);
    } else {
        type.set(0);
    }
}

我遇到了同样的问题,我使用了 onCLick 侦听器而不是 onCHeck listener 。这样,当以编程方式设置时,侦听器不会更改检查状态。 在您的问题中,您应该尝试为您的复选框设置不同的检查更改侦听器。

第一次遇到这个问题,我觉得用绑定适配器实现比较好

这里是绑定适配器的代码

interface OnUserCheckedChangeListener {
    fun onUserCheckChange(view:CompoundButton, isChecked:Boolean)
}
@BindingAdapter("onUserCheckedChange")
fun setUserCheckedChangeListener(view:CompoundButton, listener: OnUserCheckedChangeListener?){
    if(listener == null){
        view.setOnClickListener(null)
    }else{
        view.setOnClickListener {
            listener.onUserCheckChange(view, view.isChecked)
        }
    }
}

而且我们可以在任何复合按钮上使用它

<CheckBox
            android:id="@+id/finish_check"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"   
            android:checked="@{your_condition}"
            onUserCheckedChange="@{(view, checked) -> vm.onItemChecked(todo, checked)}"
            />

数据绑定非常简单

在 xml 复选框组件中

 <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onCheckedChanged="@{(compoundButton, checked) -> 
changeKeyboardVM.onCheckedChange(compoundButton, checked)}" />

在 ViewModel 或 Activity

  public void onCheckedChange(CompoundButton button, boolean check) {
    Log.d("Z1D1", "onCheckedChange: " + check);
}

现在布尔检查 true 已检查 false 未选中

使用 onClick 而不是 onCheckedChanged 来防止双向绑定。

来自item_order_view.xml:

<data>

    <variable
        name="viewModel"
        type="com.package.name.OrderItemViewModel" />
</data>

           <CheckBox
                android:id="@+id/cb_selected"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginLeft="8dp"
                android:buttonTint="@color/white"
                android:checked="@{viewModel.isSelect}"
                android:onClick="@{() -> viewModel.onClickedCheckBox()}"
                android:textColor="@color/white" />

来自OrderItemViewModel.java

public class OrderItemViewModel {

    public final ObservableField<Boolean> isSelect;
    public final OrderItemViewModelListener mListener;
    private final Order mOrder;

    public OrderItemViewModel(Order order, OrderItemViewModelListener listener) {
        this.mListener = listener;
        this.mOrder = order;

        isSelect = new ObservableField<>(mOrder != null ? mOrder.isSelect() : false);
    }

    /**
     * Using onClick instead of onCheckedChanged
     * to prevent 2-ways binding issue.
     */
    public void onClickedCheckBox() {
        mListener.onCheckChanged();
    }

    public interface OrderItemViewModelListener {
        void onCheckChanged();
    } 
}

从 ViewModel 公开一个 ObservableBoolean,然后对该布尔值使用双向数据绑定。

然后你可以使用 ObservableBoolean 的值来决定你想做什么,而不是在 XML.

中对其进行编码
android:checked="@={vm.checkedValue}"

参见:

里面写OnCheckedChangeListener:

if (button.isPressed()) {
    // A user pressed Switch.
}

也许 的一些答案可能会有所帮助,例如,定义 android:onCheckedChanged 侦听器,但我没有测试。