How can I tell if the switch is changing, the value of the checkbox is changed by the user or programmatically (including by holding)?

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

How to implement the isNotSetByUser() method?

+90
android checkbox listener onchange
Feb 03 2018-12-12T00:
source share
14 answers

Answer 2:

Very simple answer:

Use on OnClickListener instead of 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); } }); 

Now you select the click events and do not have to worry about software changes.




Answer 1:

I created a wrapper class (see Decorator Pattern) that handles this problem in an encapsulated way:

 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 can still be declared the same in XML, but use it when initializing your GUI in code:

 BetterCheckBox myCheckBox; // later... myCheckBox = new BetterCheckBox(context, (CheckBox) view.findViewById(R.id.my_check_box)); 

If you want to check the box from the code without starting the listener, call myCheckBox.silentlySetChecked(someBoolean) instead of setChecked .

+141
Jan 13 '13 at 20:11
source share

Perhaps you can check isShown ()? If TRUE - than the user. It works for me.

 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(); } } }); 
+36
Feb 03 2018-12-12T00:
source share

You can remove the listener before changing it programmatically and add it again, as indicated in the following SO message:

stack overflow

 theCheck.setOnCheckedChangeListener(null); theCheck.setChecked(false); theCheck.setOnCheckedChangeListener(toggleButtonChangeListener); 
+18
Jul 06 '15 at 15:13
source share

Inside onCheckedChanged (), just check to see if the user has actually checked / unchecked the radio button, and then do the following:

 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. } } 

});

+13
Oct 06 '17 at 10:16 on
source share

Try expanding CheckBox. Something like this (not a complete example):

 public MyCheckBox extends CheckBox { private Boolean isCheckedProgramatically = false; public void setChecked(Boolean checked) { isCheckedProgramatically = true; super.setChecked(checked); } public Boolean isNotSetByUser() { return isCheckedProgramatically; } } 
+4
03 Feb 2018-12-12T00:
source share

There is another simple solution that works very well. Example for a 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; } } 
+3
Aug 26 '14 at 17:41
source share

Interest Ask. As far as I know, once you are in the listener, you cannot determine what action caused the listener, the context is not enough. If you do not use an external logical value as an indicator.

When you check the box "programmatically", set a boolean value before indicating that it was done programmatically. Something like:

 private boolean boxWasCheckedProgrammatically = false; .... // Programmatic change: boxWasCheckedProgrammatically = true; checkBoxe.setChecked(true) 

And in your listener, do not forget to reset the state of the flag:

 @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; } 
+2
03 Feb 2018-12-12T00:
source share

Try NinjaSwitch :

Just call setChecked(boolean, true) to change the check state of the switch without detection!

 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); } } } 
+2
Jan 14 '16 at 13:50
source share

If OnClickListener already installed and should not be overwritten, use !buttonView.isPressed() as isNotSetByUser() .

Otherwise, the best option is to use OnClickListener instead of OnCheckedChangeListener .

+2
Jun 25 '17 at 2:06 on
source share

The accepted answer may be slightly simplified so as not to support the link to the original flag. This makes it so that we can use SilentSwitchCompat (or SilentCheckboxCompat , if you want) directly in XML. I also made it so that you can set OnCheckedChangeListener to null if you want to.

 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); } } 

Then you can use this directly in your XML, like this (Note: you will need the full package name):

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

Then you can check the box silently by calling:

 SilentCheckBox mySilentCheckBox = (SilentCheckBox) findViewById(R.id.my_check_box) mySilentCheckBox.silentlySetChecked(someBoolean) 
+2
Jul 06 '17 at 2:04 on
source share

Create variable

 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; } 

In the application, when you change it instead of the user, call notSetByUser(true) so that it is not set by the user, otherwise call notSetByUser(false) , that is, it will be installed by the program.

Finally, in your event listener, after calling isNotSetByUser (), make sure you change it to normal again.

Call this method whenever you process this action either through the user or programmatically. Call the notSetByUser () function with the appropriate value.

0
03 Feb 2018-12-12T00:
source share

If the presentation tag is not used, you can use it instead of expanding the check box:

  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 } 

every time you call something that checks / unchecks the box, also call this before checking / unchecking:

 checkbox.setTag(true); 
0
Jun 10 '14 at 11:48
source share

Here is my implementation

Java code for custom switch:

 public class CustomSwitch extends SwitchCompat { private OnCheckedChangeListener mListener = null; public CustomSwitch(Context context) { super(context); } public CustomSwitch(Context context, AttributeSet attrs) { super(context, attrs); } public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) { if(listener != null && this.mListener != listener) { this.mListener = listener; } super.setOnCheckedChangeListener(listener); } public void setCheckedSilently(boolean checked){ this.setOnCheckedChangeListener(null); this.setChecked(checked); this.setOnCheckedChangeListener(mListener); }} 

Equivalent Kotlin code:

 class CustomSwitch : SwitchCompat { private var mListener: CompoundButton.OnCheckedChangeListener? = null constructor(context: Context) : super(context) {} constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {} constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} override fun setOnCheckedChangeListener(@Nullable listener: CompoundButton.OnCheckedChangeListener?) { if (listener != null && this.mListener != listener) { this.mListener = listener } super.setOnCheckedChangeListener(listener) } fun setCheckedSilently(checked: Boolean) { this.setOnCheckedChangeListener(null) this.isChecked = checked this.setOnCheckedChangeListener(mListener) }} 

To change the state of a switch without starting a listener, use:

 swSelection.setCheckedSilently(contact.isSelected) 

You can track status changes as usual:

 swSelection.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // Do something } }); 

In Kotlin:

  swSelection.setOnCheckedChangeListener{buttonView, isChecked -> run { contact.isSelected = isChecked }} 
0
Sep 14 '18 at 12:32
source share

My option with Kotlin extension features:

 fun CheckBox.setCheckedSilently(isChecked: Boolean, onCheckedChangeListener: CompoundButton.OnCheckedChangeListener) { if (isChecked == this.isChecked) return this.setOnCheckedChangeListener(null) this.isChecked = isChecked this.setOnCheckedChangeListener(onCheckedChangeListener) } 

... unfortunately, we need to pass onCheckedChangeListener every time, because the CheckBox class does not have a get method for the mOnCheckedChangeListener ((

Using:

 checkbox.setCheckedSilently(true, myCheckboxListener) 
0
Jan 22 '19 at 7:39
source share