OnCheckChanged'i tetiklemeden Onay Kutusu değerini değiştirme


147

Benim için setOnCheckedChangeListeneruyguladımcheckbox

Arayabileceğim bir yol var mı

checkbox.setChecked(false);

tetiklemeden onCheckedChanged


Neden sadece doğru / yanlış bayrağı kullanmıyorsunuz? Bu sorunla başa çıkmanın en basit yolu ve sadece üç satırlık ekstra kod gibi. Cevabımı aşağıda görebilirsiniz.
Ruchir Baronia

Yanıtlar:


280

Hayır, yapamazsın. onCheckedChangedYöntem tarafından doğrudan olarak adlandırılır setChecked. Yapabilecekleriniz şunlardır:

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

Bkz CheckBox kaynağını ve uygulanmasını 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;            
    }
}

6
Nasıl almayı öneriyorsun mListener? Checkboxonun için bir alıcı yokOnCheckChangeListener
tir38 19

20
Peki, basitçe oyuna gerek yok çünkü çözümü anlamıyorsunuz. programcı tarafından oluşturulan arayüzün mListenerbir uygulamasıdır OnCheckChangedListener. Cevabım, programcının kendi uygulamasına bir referans sağladığını ima ediyor - mListener.
gölge

SetChecked () yöntemini tekrar tekrar kullanmak istiyorsanız dinleyiciyi değiştirmek verimsiz olur mu?
Ren

4
@Ren, dinleyiciyi değiştirmek yalnızca CheckBoxnesnede bir özelliğin ayarını içerir . Bunun verimsiz olduğunu söyleyemem.
Gölge

Doküman, "İşaretli radyo düğmesi değiştiğinde çağrılır. Seçim temizlendiğinde, checkId -1'dir. Bu gerçekten yanıltıcı, ya da isChecked'in de geçmesi gerekiyor.
AA_PV

69

Bu kodu OnCheckedChangeListener içine ekleyin:

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

Bu, hava checkBox durumunun programlı olarak veya kullanıcı işlemiyle değiştirildiğini anlamamıza yardımcı olacaktır.


11
Bu bir çözüm olarak işaretlenmeli, bir cazibe gibi çalışır!
Ashwin Balani

5
farkında olmak! Bu erişilebilirlik modunu bozar! isPressed (), sesli yardımcı modundan çift dokunma ile tetiklendiğinde doğru değildir.
A1m

21

Bunu başarmanın bir başka olası yolu, dinleyicinin çağrılmasını isteyip istemediğinizi seçmenizi sağlayan özel bir CheckBox kullanmaktır:

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

Kotlin versiyonu, isterseniz:

class CheckBox @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatCheckBox(context, attrs, defStyleAttr) {
    private var listener: CompoundButton.OnCheckedChangeListener? = null

    override fun setOnCheckedChangeListener(listener: CompoundButton.OnCheckedChangeListener?) {
        this.listener = listener
        super.setOnCheckedChangeListener(listener)
    }

    fun setChecked(checked: Boolean, alsoNotify: Boolean) {
        if (!alsoNotify) {
            super.setOnCheckedChangeListener(null)
            super.setChecked(checked)
            super.setOnCheckedChangeListener(listener)
            return
        }
        super.setChecked(checked)
    }

    fun toggle(alsoNotify: Boolean) {
        if (!alsoNotify) {
            super.setOnCheckedChangeListener(null)
            super.toggle()
            super.setOnCheckedChangeListener(listener)
        }
        super.toggle()
    }
}

örnek kullanımı:

checkBox.setChecked(true,false);

11

sadece setonclickListener kullanın, iyi çalışır ve bu çok basit bir yöntem, teşekkürler :)


35
Kullanıcı anahtarı kaydırdığında onClick () çağrılmaz.
James

2
Gerçekten de, kullanıcı geçişi sürüklediğinde bunu yapmak hiçbir işleyici olmadan bırakır.
Victor G

o zaman isChecked değerini nasıl alacaksınız yani true veya false?
Abhi

6

Kotlin'in uzantılarını @Shade yanıtıyla kullanma:

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

6

Bunu tökezleyen herkes için, bunu yapmanın daha basit bir yolu, onay kutusunda bir etiket kullanmak ve daha sonra bu etiketi dinleyicisinde (kod Kotlin'te) kontrol etmektir:

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

Daha sonra erişirken, değer değişikliğini yok saymak istediğinizde isChecked öğesini true olarak ayarlamadan önce etiketi true olarak ayarlayın:

checkBox.tag = true
checkBox.isChecked = true

Anlaşılabilirlik konusunda endişeleniyorsanız, anahtar gerektiren alternatif setTag yöntemini kullanarak etiketi bir anahtarla eşleyebilirsiniz. Ancak eğer hepsi tek bir sınıfa dahil edilmişse, birkaç yorum dizesi olanları açıklamak için fazlasıyla yeterli olacaktır.


4

Bu SafeCheckBox sınıfını onay kutunuz olarak kullanabilirsiniz:

public class SafeCheckBox extends AppCompatCheckBox implements CompoundButton.OnCheckedChangeListener {

    private OnSafeCheckedListener onSafeCheckedListener;

    private int mIgnoreListener = CALL_LISTENER;

    public static final int IGNORE = 0;
    public static final int CALL_LISTENER = 1;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({IGNORE, CALL_LISTENER})
    public @interface ListenerMode {
    }

    public SafeCheckBox(Context context) {
        super(context);
        init(context);
    }

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

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

    /**
     * @param checkState     change state of the checkbox to 
     * @param mIgnoreListener true to ignore the listener else listener will be  notified
     */
    public void setSafeCheck(boolean checkState, @ListenerMode int mIgnoreListener) {
        if (isChecked() == checkState) return; //already in the same state no need to fire listener. 

        if (onSafeCheckedListener != null) { // this to avoid a bug if the user listens for the event after using this method and in that case he will miss first check
            this.mIgnoreListener = mIgnoreListener;
        } else {
            this.mIgnoreListener = CALL_LISTENER;
        }
        setChecked(checkState);
    }

    private void init(Context context) {
        setOnCheckedChangeListener(this);
    }


    public OnSafeCheckedListener getOnSafeCheckedListener() {
        return onSafeCheckedListener;
    }

    public void setOnSafeCheckedListener(OnSafeCheckedListener onSafeCheckedListener) {
        this.onSafeCheckedListener = onSafeCheckedListener;
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

        if (onSafeCheckedListener != null)
            onSafeCheckedListener.onAlwaysCalledListener(buttonView, isChecked);// this has to be called before onCheckedChange
        if (onSafeCheckedListener != null && (mIgnoreListener == CALL_LISTENER)) {
            onSafeCheckedListener.onCheckedChanged(buttonView, isChecked);
        }
        mIgnoreListener = CALL_LISTENER;
    }

    /**
     * Listener that will be called when you want it to be called.
     * On checked change listeners are called even when the setElementChecked is called from code. :(
     */
    public interface OnSafeCheckedListener extends OnCheckedChangeListener {
        void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked);
    }
}
  • O zaman arayabilirsiniz: -

    setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified


3

Radyo düğmesini kontrol etmeden önceListener öğesini null olarak ayarlayın. Radyo düğmesini kontrol ettikten sonra dinleyiciyi tekrar ayarlayabilirsiniz.

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

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

   }
});

1
İşi yapar ve buradaki diğer çözümlerden çok daha hızlı ve basittir.
PayToPwn

3

Benim için en kolay olduğunu düşündüğüm yorum
yardımcı olabilir)

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

kullan

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

kullanımı tüm setChecked(boolean)işlevi tetikleyecek

KOTLIN

class MyCheckBox @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = R.attr.switchStyle
) : AppCompatCheckBox(context, attrs, defStyleAttr) {

    var programmatically = false

    override fun setChecked(checked: Boolean) {
        programmatically = false
        super.setChecked(checked)
    }

    fun setCheckedProgrammatically(checked: Boolean) {
        programmatically = true
        super.setChecked(checked)
    }
}

2

Bu benim kullandığım basit bir çözüm:
Özel bir dinleyici tanımlayın:

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

Başlatma:

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

Kullanımı:

checkBoxListener.disable();

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

checkBoxListener.enable();

2

Buna ne dersin. Etiketi Görünümde kullanmaya çalışın

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

ve

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
            }

        }
    });

2

A kullandım ReentrantLockve her ayarladığımda kilitledim 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

Yukarıdaki tüm cevapları çok karmaşık buldum. Neden sadece basit bir boole ile kendi bayrağınızı yaratmıyorsunuz?

Boole ile basit bir bayrak sistemi kullanın. Oluşturun boolean noListener. Herhangi bir kod çalıştırmadan anahtarınızı açmak / kapatmak istediğinizde (bu örnekte, olarak temsil edilir runListenerCode(), noListener=truearamadan önce ayarlayınswitch.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;
               }
           });

Basit bayrakları kullanarak çok basit bir çözüm. Sonunda, noListener=falsekodumuzun çalışmaya devam etmesi için bir kez daha ayarladık . Bu yardımcı olur umarım!


1

Bu deneyin sizin için çalışması gerekir! Bunu firebase ile de kullanabilirsiniz!

Firebase verileri almak için! Bunu kullan!

databaseReference.child(user.getPhoneNumber()).child("Reqs").addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            SharedPreferences prefs = mContext.getSharedPreferences("uinfo", MODE_PRIVATE);
            String pno = prefs.getString("username", "No name defined");

            if(dataSnapshot.child(pno).getValue(String.class).equals("acc")){
                holder.acc.setChecked(true);
            }else{
                holder.acc.setChecked(false);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            // Getting Post failed, log a message
            Log.w("dfs", "loadPost:onCancelled", databaseError.toException());
            // ...
        }
    });

Bundan sonra kullanıcı bir şey yaptığında!

holder.acc.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked) {
                    if(buttonView.isPressed()) {
                        //your code
                    }
                }
                else {
                    if(buttonView.isPressed()) {
                       //your code
                    }
                }
            }
        });

1

Kontrol ettiğimiz her enabledayarda dinleyiciyi geçmek zorunda kalmak istemedim, ne de değeri ayarlamamız gerekip gerekmediğini belirlemenin bir yolu olarak (değeri ayarlarken anahtarın devre dışı bırakılması durumunda ne olur) ?)

Bunun yerine, bir kimliğe sahip etiketleri ve arayabileceğiniz birkaç uzantı yöntemini kullanıyorum:

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

Şimdi arayabilir setCheckedWithoutCallingListener(bool)ve doğru dinleyici kullanımını zorlar.

setChecked(bool)Hala ihtiyacınız varsa dinleyiciyi ateşlemeye de çağırabilirsiniz


0

Sanırım yansıma kullanmak tek yoldur. Bunun gibi bir şey:

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

Devs değişim alan adı ya da, örneğin kadar çalışabilirler, en az eklenti gibi bir şey ... yöntem hiyerarşisinde "isChecked" yukarı çekin ... ya da başka bir üstlenmeden yapmakif(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
aeracode

API'yı kırmayı ve dahili bilgilere girmeyi teşvik etmek yanlış bir fikirdir. Uygulamada yapılacak herhangi bir değişiklik, uygulamaların başarısız olmasına neden olur.
mspanc

0

@Chris cevap dayalı java yazılmış çözüm:

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 onay kutusu ve her zaman biri işaretlenecektir (biri başlangıçta işaretlenmelidir). Etiketi doğru bloklar üzerinde ayarlamaCheckedChanged listener.


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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.