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
侦听器,但我没有测试。
我现在正在尝试在我的项目中使用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
侦听器,但我没有测试。