Android - programmatically change the state of a switch without triggering OnCheckChanged listener

JavaAndroidOnclicklistenerOncheckedchangedAndroid Switch

Java Problem Overview



I'm looking for a method of programmatically changing the state of an Android Switch widget using switch.setChecked(true); without triggering OnCheckedChangedlistener.

My first thought was to swap it out for an OnClickListener but as this only registers clicks and you are able to not only click but also slide a Switch then it's not really fit for purpose as if the user was to slide the Switch from off to on then the Switch would actually do nothing as the user is not clicking...

If anyone's got a solution or a smart work around for this, that would be awesome

Java Solutions


Solution 1 - Java

Set the listener to null before calling setCheck() function, and enable it after that, such as the following:

switch.setOnCheckedChangeListener (null);
switch.setChecked(true);
switch.setOnCheckedChangeListener (this);

Reference: Change Checkbox value without triggering onCheckChanged

Solution 2 - Java

Every CompoundButton (two states button - on/off) has a pressed state which is true only when a user is pressing the view.

Just add a check in your listener before starting the actual logic:

if(compoundButton.isPressed()) {
    // continue with your listener
}

That way, changing the checked value programmatically won't trigger the unwanted code.

From @krisDrOid answer.

Solution 3 - Java

Well, just before doing things in code with the switch you could just unregister the Listener, then do whatever you need to, and again register the listener.

Solution 4 - Java

I have one solution and its working fine at my end. I have added setOnTouchListener and setOnCheckedChangeListener on my switch control, and added following code to solve my problem.

    // set tag by default.
    mMySwitch.setTag("TAG");
        
    // Add OnCheckedChangeListener.
    mMySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (mMySwitch.getTag() != null) {
                 mMySwitch.setTag(null);
                 return;
                }
                                                                           
          // Do your stuff here.
        }
    });
            
    // Add Touch listener.
    mMySwitch.setOnTouchListener(new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
            mMySwitch.setTag(null);
            return false;
         }
    });

In this way setOnCheckedChangeListener is getting called only when check changed happens by human intervention by drag, by click, by touch.

Also don't forgot to add your valid string tag ( not null ) when your trying to change check status of switch control. like :

 mMySwitch.setTag("TAG");
 mMySwitch.setChecked(true);

Solution 5 - Java

Write a custom Switch or SwitchCompat and override the setOnCheckedListener.

public class SwitchCompat extends android.support.v7.widget.SwitchCompat {
private boolean mIgnoreCheckedChange = false;

public SwitchCompat(Context context) {
    super(context);
}

public SwitchCompat(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public SwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


@Override
public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {
    super.setOnCheckedChangeListener(new OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (mIgnoreCheckedChange) {
                return;
            }
            listener.onCheckedChanged(buttonView, isChecked);
        }
    });
}

public void setChecked(boolean checked, boolean notify) {
    mIgnoreCheckedChange = !notify;
    setChecked(checked);
    mIgnoreCheckedChange = false;
}

}

Solution 6 - Java

the best solution I can find is;

const val SWITCH_COMPAT_IGNORE_TAG = "SWITCH_COMPAT_IGNORE_TAG"

fun SwitchCompat.isCheckedWithIgnoreTag(isChecked: Boolean) {
    tag = SWITCH_COMPAT_IGNORE_TAG
    this.isChecked = isChecked
    tag = null
}

switchCompat.isCheckedWithIgnoreTag(true)

switchCompat.setOnCheckedChangeListener { buttonView, isChecked ->
    if (buttonView.tag != SWITCH_COMPAT_IGNORE_TAG) {
        //TODO
    }
}

Solution 7 - Java

For the default switch writed <Switch/> on xml, do this in kotlin to set it programmatically :

mySwitch.isChecked = true

Then, if you want to do some action when user click on it:

 mySwitch.setOnCheckedChangeListener { compoundButton, isChecked ->
            when (isChecked) {
                true -> { /* do something here*/ }
                false -> { /* do something here*/ }
            }
        }

Solution 8 - Java

Elaborating on Mahmoud's answer

CompoundButton.OnCheckedChangeListener switchListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    switchListener = new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                //Implement on check change
            }
        }; 
      switch.setOnCheckedChangeListener (switchListener);

      //When you want to trigger the checked of switch do the following
      switch.setOnCheckedChangeListener (null);
      switch.setChecked(true);
      switch.setOnCheckedChangeListener (switchListener);
     }

`

Solution 9 - Java

use this switch.setChecked(true); // first set value (from pref or server or anywhere) and than switch.setOnCheckedChangeListener (this); add listener.

Solution 10 - Java

If nothing worked here is a tricky solution.

Create a textview on top of the switch and add clickListener to textview.

 <TextView
        android:elevation="1dp"
        android:id="@+id/switchLabel"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text=""
        app:layout_constraintBottom_toBottomOf="@id/switch1"
        app:layout_constraintStart_toStartOf="@+id/switch1"
        app:layout_constraintTop_toTopOf="@id/switch1"
        app:layout_constraintEnd_toEndOf="@id/switch1" />

Add elavation to textview.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaul AlexanderView Question on Stackoverflow
Solution 1 - JavaMahmoud IbrahimView Answer on Stackoverflow
Solution 2 - JavaronginatView Answer on Stackoverflow
Solution 3 - JavasmnplView Answer on Stackoverflow
Solution 4 - JavaChetan BhoyarView Answer on Stackoverflow
Solution 5 - Javahyb1996View Answer on Stackoverflow
Solution 6 - JavaCafer Mert CeyhanView Answer on Stackoverflow
Solution 7 - JavaMakiXView Answer on Stackoverflow
Solution 8 - JavaIsmail IqbalView Answer on Stackoverflow
Solution 9 - Javanilesh prajapatiView Answer on Stackoverflow
Solution 10 - JavaAthiraView Answer on Stackoverflow