setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// How to check whether the checkbox/switch has been checked
// by user or it has been checked programatically ?
if (isNotSetByUser())
return;
handleSetbyUser();
}
});
如何实施方法isNotSetByUser()
?
答案 0 :(得分:145)
答案2:
一个非常简单的答案:
使用OnClickListener而不是OnCheckedChangeListener
someCheckBox.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// you might keep a reference to the CheckBox to avoid this class cast
boolean checked = ((CheckBox)v).isChecked();
setSomeBoolean(checked);
}
});
现在,您只需选择点击事件,而无需担心程序化更改。
答案1:
我创建了一个包装类(参见Decorator Pattern),它以封装的方式处理这个问题:
public class BetterCheckBox extends CheckBox {
private CompoundButton.OnCheckedChangeListener myListener = null;
private CheckBox myCheckBox;
public BetterCheckBox(Context context) {
super(context);
}
public BetterCheckBox(Context context, CheckBox checkBox) {
this(context);
this.myCheckBox = checkBox;
}
// assorted constructors here...
@Override
public void setOnCheckedChangeListener(
CompoundButton.OnCheckedChangeListener listener){
if(listener != null) {
this.myListener = listener;
}
myCheckBox.setOnCheckedChangeListener(listener);
}
public void silentlySetChecked(boolean checked){
toggleListener(false);
myCheckBox.setChecked(checked);
toggleListener(true);
}
private void toggleListener(boolean on){
if(on) {
this.setOnCheckedChangeListener(myListener);
}
else {
this.setOnCheckedChangeListener(null);
}
}
}
CheckBox仍然可以在XML中声明相同,但在代码中初始化GUI时使用它:
BetterCheckBox myCheckBox;
// later...
myCheckBox = new BetterCheckBox(context,
(CheckBox) view.findViewById(R.id.my_check_box));
如果您想在不触发听众的情况下从代码设置检查,请拨打myCheckBox.silentlySetChecked(someBoolean)
而不是setChecked
。
答案 1 :(得分:36)
也许你可以检查isShown()?如果为TRUE - 而不是它的用户。适合我。
setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (myCheckBox.isShown()) {// makes sure that this is shown first and user has clicked/dragged it
doSometing();
}
}
});
答案 2 :(得分:18)
您可以在以编程方式更改之前删除侦听器并再次添加,如下面的SO帖子所示:
https://stackoverflow.com/a/14147300/1666070
public function updateHover(e:MouseEvent):void
{
var p:Point=pointToXY(e.localX,e.localY);
_tileHover.visible = false; // hide hover for now
if ((p.y<0) || (p.y>=tileArray.length)) return; // range error on Y
if ((p.x<0)||(p.x>=tileArray[p.y].length)) return; // range error on X
if (!tileArray[p.y][p.x]) return; // no tile
var _tile:Tile=tileArray[p.y][p.x];
_tileHover.x=_tile.x;
_tileHover.y=_tile.y; // no need to convert xyToPoint() we have coords stored in tile
_tileHover.visible=true;
}
答案 3 :(得分:14)
在onCheckedChanged()内部,只检查用户是否实际检查/取消选中了单选按钮,然后按如下方式执行相应操作:
mMySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.isPressed()) {
// User has clicked check box
}
else
{
//triggered due to programmatic assignment using 'setChecked()' method.
}
}
});
答案 4 :(得分:4)
尝试扩展CheckBox。这样的事情(不是完整的例子):
public MyCheckBox extends CheckBox {
private Boolean isCheckedProgramatically = false;
public void setChecked(Boolean checked) {
isCheckedProgramatically = true;
super.setChecked(checked);
}
public Boolean isNotSetByUser() {
return isCheckedProgramatically;
}
}
答案 5 :(得分:3)
另一个简单的解决方案非常有效。示例适用于Switch。
public class BetterSwitch extends Switch {
//Constructors here...
private boolean mUserTriggered;
// Use it in listener to check that listener is triggered by the user.
public boolean isUserTriggered() {
return mUserTriggered;
}
// Override this method to handle the case where user drags the switch
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean result;
mUserTriggered = true;
result = super.onTouchEvent(ev);
mUserTriggered = false;
return result;
}
// Override this method to handle the case where user clicks the switch
@Override
public boolean performClick() {
boolean result;
mUserTriggered = true;
result = super.performClick();
mUserTriggered = false;
return result;
}
}
答案 6 :(得分:2)
有趣的问题。据我所知,一旦你进入监听器,就无法检测到哪个动作触发了监听器,上下文是不够的。除非您使用外部布尔值作为指标。
当您选中“以编程方式”框时,请先设置一个布尔值,以表明它是以编程方式完成的。类似的东西:
private boolean boxWasCheckedProgrammatically = false;
....
// Programmatic change:
boxWasCheckedProgrammatically = true;
checkBoxe.setChecked(true)
在你的听众中,不要忘记重置复选框的状态:
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isNotSetByUser()) {
resetBoxCheckSource();
return;
}
doSometing();
}
// in your activity:
public boolean isNotSetByUser() {
return boxWasCheckedProgrammatically;
}
public void resetBoxCheckedSource() {
this.boxWasCheckedProgrammatically = false;
}
答案 7 :(得分:2)
尝试NinjaSwitch
:
只需拨打setChecked(boolean, true)
即可更改未经检测到的交换机已检查状态!
public class NinjaSwitch extends SwitchCompat {
private OnCheckedChangeListener mCheckedChangeListener;
public NinjaSwitch(Context context) {
super(context);
}
public NinjaSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NinjaSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
super.setOnCheckedChangeListener(listener);
mCheckedChangeListener = listener;
}
/**
* <p>Changes the checked state of this button.</p>
*
* @param checked true to check the button, false to uncheck it
* @param isNinja true to change the state like a Ninja, makes no one knows about the change!
*/
public void setChecked(boolean checked, boolean isNinja) {
if (isNinja) {
super.setOnCheckedChangeListener(null);
}
setChecked(checked);
if (isNinja) {
super.setOnCheckedChangeListener(mCheckedChangeListener);
}
}
}
答案 8 :(得分:2)
如果OnClickListener
已设置且不应被覆盖,请使用!buttonView.isPressed()
作为isNotSetByUser()
。
否则,最好的变体是使用OnClickListener
而不是OnCheckedChangeListener
。
答案 9 :(得分:2)
接受的答案可以简化一点,以保持对原始复选框的引用。这使得我们可以直接在XML中使用SilentSwitchCompat
(或SilentCheckboxCompat
,如果您愿意)。我也做了,所以如果你愿意的话,可以将OnCheckedChangeListener
设置为null
。
public class SilentSwitchCompat extends SwitchCompat {
private OnCheckedChangeListener listener = null;
public SilentSwitchCompat(Context context) {
super(context);
}
public SilentSwitchCompat(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
super.setOnCheckedChangeListener(listener);
this.listener = listener;
}
/**
* Check the {@link SilentSwitchCompat}, without calling the {@code onCheckChangeListener}.
*
* @param checked whether this {@link SilentSwitchCompat} should be checked or not.
*/
public void silentlySetChecked(boolean checked) {
OnCheckedChangeListener tmpListener = listener;
setOnCheckedChangeListener(null);
setChecked(checked);
setOnCheckedChangeListener(tmpListener);
}
}
然后您可以直接在XML中使用它(注意:您将需要整个包名称):
<com.my.package.name.SilentCheckBox
android:id="@+id/my_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="@string/disabled"
android:textOn="@string/enabled"/>
然后你可以通过调用以下方式静默检查该框:
SilentCheckBox mySilentCheckBox = (SilentCheckBox) findViewById(R.id.my_check_box)
mySilentCheckBox.silentlySetChecked(someBoolean)
答案 10 :(得分:1)
我的带有Kotlin扩展功能的变体:
fun CheckBox.setCheckedSilently(isChecked: Boolean, onCheckedChangeListener: CompoundButton.OnCheckedChangeListener) {
if (isChecked == this.isChecked) return
this.setOnCheckedChangeListener(null)
this.isChecked = isChecked
this.setOnCheckedChangeListener(onCheckedChangeListener)
}
...不幸的是,我们每次都需要传递onCheckedChangeListener,因为CheckBox类没有为mOnCheckedChangeListener字段((
用法:
checkbox.setCheckedSilently(true, myCheckboxListener)
答案 11 :(得分:1)
这应该足够了:
SwitchCompact.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (buttonView.isPressed()) {
if (!isChecked) {
//do something
} else {
// do something else
}
}
});
答案 12 :(得分:0)
创建变量
boolean setByUser = false; // Initially it is set programmatically
private void notSetByUser(boolean value) {
setByUser = value;
}
// If user has changed it will be true, else false
private boolean isNotSetByUser() {
return setByUser;
}
在应用程序中更改而不是用户时,请调用notSetByUser(true)
以使其不被用户设置,否则请调用notSetByUser(false)
,即由程序设置。
最后,在您的事件监听器中,在调用isNotSetByUser()之后,请确保再次将其更改回正常状态。
每当您通过用户或以编程方式处理该操作时,请调用此方法。使用适当的值调用notSetByUser()。
答案 13 :(得分:0)
如果未使用视图标记,则可以使用它而不是扩展复选框:
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
if (buttonView.getTag() != null) {
buttonView.setTag(null);
return;
}
//handle the checking/unchecking
}
每当您调用选中/取消选中复选框的内容时,也请在选中/取消选中之前调用此方法:
checkbox.setTag(true);
答案 14 :(得分:0)
我已经使用RxJava的PublishSubject
(简单的扩展名)创建了扩展名。仅对“ OnClick”事件做出反应。
/**
* Creates ClickListener and sends switch state on each click
*/
fun CompoundButton.onCheckChangedByUser(): PublishSubject<Boolean> {
val onCheckChangedByUser: PublishSubject<Boolean> = PublishSubject.create()
setOnClickListener {
onCheckChangedByUser.onNext(isChecked)
}
return onCheckChangedByUser
}