web-dev-qa-db-fra.com

Changer la valeur de la case à cocher sans déclencher onCheckedChanged

J'ai setOnCheckedChangeListener implémenté pour ma checkbox

Puis-je appeler

checkbox.setChecked(false);

sans déclencher la onCheckedChanged

109
Archie.bpgc

Non, tu ne peux pas le faire. La méthode onCheckedChanged est appelée directement à partir de setChecked. Ce que vous pouvez faire est le suivant:

mCheck.setOnCheckedChangeListener (null);
mCheck.setChecked (false);
mCheck.setOnCheckedChangeListener (mListener);

Voir la source de CheckBox , et l'implémentation de setChecked:

public void  setChecked(boolean checked) {
    if (mChecked != checked) {
        mChecked = checked;
        refreshDrawableState();

        // Avoid infinite recursions if setChecked() is called from a listener
        if (mBroadcasting) {
            return;
        }

        mBroadcasting = true;
        if (mOnCheckedChangeListener != null) {
            mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
        }

        if (mOnCheckedChangeWidgetListener != null) {
            mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
        }

        mBroadcasting = false;            
    }
}
234
Shade

Un autre moyen possible d'y parvenir consiste à utiliser une CheckBox personnalisée, qui vous permettra de choisir si vous souhaitez appeler l'auditeur ou non:

public class CheckBox extends AppCompatCheckBox {
    private OnCheckedChangeListener mListener;

    public CheckBox(final Context context) {
        super(context);
    }

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

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

    @Override
    public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {
        mListener = listener;
        super.setOnCheckedChangeListener(listener);
    }

    public void setChecked(final boolean checked, final boolean alsoNotify) {
        if (!alsoNotify) {
            super.setOnCheckedChangeListener(null);
            super.setChecked(checked);
            super.setOnCheckedChangeListener(mListener);
            return;
        }
        super.setChecked(checked);
    }

    public void toggle(boolean alsoNotify) {
        if (!alsoNotify) {
            super.setOnCheckedChangeListener(null);
            super.toggle();
            super.setOnCheckedChangeListener(mListener);
        }
        super.toggle();
    }
}

exemple d'utilisation:

checkBox.setChecked(true,false);
17
android developer

vous utilisez simplement setonclickListener, cela fonctionnera très bien et ceci est une méthode très simple, merci :)

12
Rohit

Ajoutez ce code dans OnCheckedChangeListener: 

if(!compoundButton.isPressed()) {
            return;
}

Cela nous aidera à comprendre que l'état de checkBox météo a été modifié par programme ou par l'action de l'utilisateur.

6
krisDrOid

En utilisant les extensions de Kotlin avec @Shade, vous répondez:

fun CompoundButton.setCustomChecked(value: Boolean,listener: CompoundButton.OnCheckedChangeListener) {
     setOnCheckedChangeListener(null)
     isChecked = value
     setOnCheckedChangeListener(listener)
}
5
Mickey Mouse

Pour tous ceux qui tombent sur cela, une façon plus simple de le faire est simplement d'utiliser une balise sur la case à cocher puis de vérifier cette balise sur son écouteur (le code est en Kotlin):

checkBox.tag = false
checkBox.setOnCheckedChangeListener{ buttonView, isChecked -> 
    if(checkBox.tag != true) {
        //Do some stuff
    } else {
        checkBox.tag = false
    }

Ensuite, lors de l'accès, définissez simplement la balise sur true avant de définir isChecked sur true lorsque vous souhaitez ignorer le changement de valeur:

checkBox.tag = true
checkBox.isChecked = true

Vous pouvez également mapper le tag sur une clé en utilisant la méthode alternative setTag qui nécessite une clé si vous êtes inquiet pour la compréhensibilité. Mais si tout est contenu dans une seule classe, quelques chaînes de commentaires seront plus que suffisantes pour expliquer ce qui se passe.

3
Chris

Définissez la valeur null sur changeListener avant de cocher le bouton radio. Vous pouvez réactiver l'auditeur après avoir coché le bouton radio.

radioGroup.setOnCheckedChangeListener(null);
radioGroup.check(R.id.radioButton);
radioGroup.setOnCheckedChangeListener(new 

RadioGroup.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(RadioGroup radioGroup, @IdRes int i) {

   }
});
2
gencaysahinn

C'est une solution simple que j'ai utilisée:
Définir un auditeur personnalisé:

class CompoundButtonListener implements CompoundButton.OnCheckedChangeListener {

    boolean enabled = false;

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {

    }

    void enable() {
        enabled = true;
    }

    void disable() {
        enabled = false;
    }

    boolean isEnabled() {
        return enabled;
    }
}

Initialisation:

CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
        if (isEnabled()) {
            // Your code goes here
        }
    }
};
myCheckBox.setOnCheckedChangeListener(checkBoxListener);

Utilisation:

checkBoxListener.disable();

// Some logic based on which you will modify CheckBox state
// Example: myCheckBox.setChecked(true)

checkBoxListener.enable();
2
vovahost

Mon interprétation que je pense être la plus facile
Peut être utile)

public class ProgrammableSwitchCompat extends SwitchCompat {

    public boolean isCheckedProgrammatically = false;

    public ProgrammableSwitchCompat(final Context context) {
        super(context);
    }

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

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

    @Override
    public void setChecked(boolean checked) {
        isCheckedProgrammatically = false;
        super.setChecked(checked);
    }

    public void setCheckedProgrammatically(boolean checked) {
        isCheckedProgrammatically = true;
        super.setChecked(checked);
    }
}

utilise le

@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean on) {
    if (((ProgrammableSwitchCompat) compoundButton).isCheckedProgrammatically) {
        return;
    }
    //...
    ((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(true);
    //...
    ((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(false);
    //...
}

l'utilisation déclenchera la fonction setChecked(boolean)
c'est tout

2
V. Kalyuzhnyu

J'ai trouvé toutes les réponses ci-dessus trop compliquées. Pourquoi ne pas simplement créer votre propre drapeau avec un simple booléen?

Utilisez simplement un système de drapeau simple avec un booléen. Créez boolean noListener. Chaque fois que vous souhaitez activer/désactiver votre commutateur sans exécuter de code (dans cet exemple, représenté par runListenerCode(), définissez simplement noListener=true avant d'appeler switch.setChecked(false/true).

switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
           @Override
           public void onCheckedChanged(CompoundButton compoundButton, boolean selected) {
               if (!noListener) { //If we want to run our code like usual
                   runListenerCode();
               } else { //If we simply want the switch to turn off
                   noListener = false;
               }
           });

Solution très simple utilisant des drapeaux simples. À la fin, nous redéfinissons noListener=false pour que notre code continue à fonctionner. J'espère que cela t'aides!

1
Ruchir Baronia

J'ai utilisé un ReentrantLock et le verrouille chaque fois que je règle isChecked:

// lock when isChecked is being set programmatically
val isBeingProgrammaticallySet = ReentrantLock()

// set isChecked programmatically
isBeingProgrammaticallySet.withLock()
{
    checkbox.isChecked = true
}

// do something only when preference is modified by user
checkbox.setOnCheckedChangeListener()
{
    _,isChecked ->
    if (isBeingProgrammaticallySet.isHeldByCurrentThread.not())
    {
        // do it
    }
}
1
Eric

Je suppose que l'utilisation de la réflexion est le seul moyen. Quelque chose comme ça:

CheckBox cb = (CheckBox) findViewById(R.id.checkBox1);
try {
    Field field = CompoundButton.class.getDeclaredField("mChecked");
    field.setAccessible(true);
    field.set(cb, cb.isChecked());
    cb.refreshDrawableState();
    cb.invalidate();
} catch (Exception e) {
    e.printStackTrace();
}
1
Zielony

Que diriez-vous de ceci . Essayez d'utiliser Tag in View

mCheck.setTag("ignore");
mCheck.setChecked(true);
mCheck.setTag(null);

et

switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean selected) {

            //If switch has a tag, ignore below
            if(compoundButton.getTag() != null)
                return; 

            if (selected) {
                // do something
            } else {
                // do something else
            }

        }
    });
0
areema

Ma solution écrite en Java basée sur la réponse @Chris:

chkParent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(buttonView.getTag() != null){
                    buttonView.setTag(null);
                    return;
                }
                if(isChecked){
                    chkChild.setTag(true);
                    chkChild.setChecked(false);
                }
                else{
                    chkParent.setChecked(true);
                }
            }
});

chkChild.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(buttonView.getTag() != null){
                    buttonView.setTag(null);
                    return;
                }
                if(isChecked){
                    chkParent.setTag(true);
                    chkParent.setChecked(false);
                }
                else{
                    chkChild.setChecked(true);
                }
            }
});

2 cases à cocher et toujours une sera cochée (une doit être cochée au départ si). Définition de la balise sur true blocks onCheckedChanged listener.

0
Makalele
public void setCheckedChangeListenerSwitch() {

    switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean selected) {

            if (selected) {
                // do something
            } else {
                // do something else
            }

        }
    });

}

// Update state & reset listener (so onCheckedNot called)
public void updateSwitchState(boolean state){

    switch.setOnCheckedChangeListener(null);
    switch.setChecked(state);
    setCheckedChangeListenerSwitch();

}
0
codebyjames