【问题标题】:android databinding: how to avoid onCheckedChanged triggered by programmaticallyandroid数据绑定:如何避免以编程方式触发的onCheckedChanged
【发布时间】:2017-07-28 17:44:19
【问题描述】:

我现在尝试在我的项目中使用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);
    }
}

【问题讨论】:

    标签: android checkbox data-binding android-databinding


    【解决方案1】:

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

    然后你可以使用 ObservableBoolean 的值来决定你想要做什么,而不是在 XML 中编码。

    android:checked="@={vm.checkedValue}"
    

    【讨论】:

    • 请显示一些代码。我不明白,你做了什么?
    • @CoolMind 缺少的代码只是private val observableBoolean = ObservableBoolean(false)
    【解决方案2】:

    数据绑定非常简单

    在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 未选中

    【讨论】:

    • 你没有解决问题,因为你没有设置android:checked。
    【解决方案3】:

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

    【讨论】:

    • 那么如何区分是选中还是取消选中?处理时获取当前状态?它应该能够工作。顺便说一句,谷歌是如此愚蠢?没有优雅的解决方案?
    • 我已经尝试了您的解决方案(检查问题的更新),它适用于我的环境。但我正在考虑复选框的状态是否总是正确的。当点击回调被触发时,复选框的状态总是更新?
    • 是的,复选框的状态将自动更改,在侦听器内部,您必须检查其状态然后采取相应措施。
    • 每次点击都会勾选/取消勾选。不用担心
    • 是的,每次状态都应该改变,但我担心的是:状态改变是否总是在onclick回调被调用之前发生。
    【解决方案4】:

    我第一次遇到这个问题,我认为最好使用绑定适配器来实现。

    这是绑定适配器的代码

    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)}"
                />
    

    【讨论】:

    • 它有什么帮助? onUserCheckedChange 是否在 android:checked 设置后调用?滑动时会引发onCheckedChanged 事件吗?
    【解决方案5】:

    使用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();
        } 
    }
    

    【讨论】:

    • 如何处理滑动?
    【解决方案6】:

    见https://stackoverflow.com/a/52606437/2914140:

    在OnCheckedChangeListener里面写:

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

    也许How to use data binding for Switch onCheckedChageListener event? 的一些答案可能会有所帮助,例如,定义android:onCheckedChanged 侦听器,但我没有测试。

    【讨论】:

      猜你喜欢
      • 2014-07-17
      • 1970-01-01
      • 1970-01-01
      • 2019-12-11
      • 2012-04-24
      • 2017-03-27
      • 2017-07-15
      • 2014-04-22
      • 1970-01-01
      相关资源
      最近更新 更多