189 votes

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

J'ai setOnCheckedChangeListener mis en œuvre pour mon checkbox

Y a-t-il un moyen pour que je puisse appeler

checkbox.setChecked(false);

sans déclencher la onCheckedChanged

1voto

Ruchir Baronia Points 2023

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

Il suffit d'utiliser un simple système de drapeau avec un booléen. Créer boolean noListener . Chaque fois que vous voulez activer/désactiver votre interrupteur sans exécuter de code (dans cet exemple, représenté sous la forme de runListenerCode() il suffit de mettre 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. A la fin, nous mettons noListener=false une fois de plus pour que notre code continue à fonctionner. J'espère que cela vous aidera !

1voto

Eric Points 2795

J'ai utilisé un ReentrantLock et le verrouiller quand je suis en train de régler isChecked :

Kotlin :

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

0voto

Zielony Points 1229

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

0voto

Makalele Points 3689

Ma solution écrite en java basée sur la réponse de @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 l'une d'entre elles sera cochée (l'une d'entre elles doit cependant être cochée au départ). Le fait de mettre le tag à true bloque l'écouteur onCheckedChanged.

0voto

Jim Points 113

Je ne voulais pas vraiment avoir à passer l'écouteur à chaque fois que l'on vérifiait les changements, ni utiliser la fonction enabled comme moyen de déterminer si nous devons définir la valeur (que se passe-t-il dans le cas où nous avons déjà désactivé l'interrupteur lors de la définition de la valeur ?)

Au lieu de cela, j'utilise des balises avec un identifiant et quelques méthodes d'extension que vous pouvez appeler :

fun CompoundButton.setOnCheckedWithoutCallingChangeListener(
    listener: (view: CompoundButton, checked: Boolean) -> Unit
) {
    setOnCheckedChangeListener { view, checked ->
        if (view.getTag(R.id.compound_button_checked_changed_listener_disabled) != true) {
            listener(view, checked)
        }
    }
    this.setTag(R.id.compound_button_enabled_checked_change_supported, true)
}

fun CompoundButton.setCheckedWithoutCallingListener(checked: Boolean) {
    check(this.getTag(R.id.compound_button_enabled_checked_change_supported) == true) {
        "Must set listener using `setOnCheckedWithoutCallingChangeListener` to call this method" 
    }

    setTag(R.id.compound_button_checked_changed_listener_disabled, true)
    isChecked = checked
    setTag(R.id.compound_button_checked_changed_listener_disabled, false)
}

Vous pouvez maintenant appeler setCheckedWithoutCallingListener(bool) et il appliquera l'utilisation correcte de l'écouteur.

Vous pouvez aussi toujours appeler setChecked(bool) pour renvoyer l'écouteur si vous en avez encore besoin

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X