android数据绑定:如何避免以编程方式触发的onCheckedChanged
Posted
技术标签:
【中文标题】android数据绑定:如何避免以编程方式触发的onCheckedChanged【英文标题】:android databinding: how to avoid onCheckedChanged triggered by programmatically 【发布时间】:2017-07-28 17:44:19 【问题描述】:我现在尝试在我的项目中使用android数据绑定,并遇到这种问题,例如:我有3个复选框作为复选框组,如果选中第一个复选框,则变量type
为1 . 第二个使type
变为2,第三个使type
变为3。所以我以这种方式实现代码。
// layout.xml
<android.support.v7.widget.AppCompatCheckBox
android:layout_
android:layout_
android:checked="@userInfoViewModel.type == 1"
android:onCheckedChanged="@(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 1)"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_
android:layout_
android:checked="@userInfoViewModel.type == 2"
android:onCheckedChanged="@(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 2)"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_
android:layout_
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);
【问题讨论】:
【参考方案1】:从 ViewModel 公开一个 ObservableBoolean,然后在该布尔值上使用双向数据绑定。
然后你可以使用 ObservableBoolean 的值来决定你想要做什么,而不是在 XML 中编码。
android:checked="@=vm.checkedValue"
【讨论】:
请显示一些代码。我不明白,你做了什么? @CoolMind 缺少的代码只是private val observableBoolean = ObservableBoolean(false)
【参考方案2】:
数据绑定非常简单
在xml复选框组件中
<CheckBox
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
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://***.com/a/52606437/2914140:
在OnCheckedChangeListener
里面写:
if (button.isPressed())
// A user pressed Switch.
也许How to use data binding for Switch onCheckedChageListener event? 的一些答案可能会有所帮助,例如,定义android:onCheckedChanged
侦听器,但我没有测试。
【讨论】:
以上是关于android数据绑定:如何避免以编程方式触发的onCheckedChanged的主要内容,如果未能解决你的问题,请参考以下文章