2013-03-20 9 views

Odpowiedz

193

Nie, nie mogę tego zrobić . Metoda onCheckedChanged jest wywoływana bezpośrednio z setChecked. Co można zrobić, jest następujący:

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

Zobacz source of CheckBox i realizacja 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;    
    } 
} 
+4

Jak można zaproponować, aby 'mListener'? 'Checkbox' nie ma gettera dla jego' OnCheckChangeListener' – tir38

+10

No cóż, nie trzeba się zgodzić tylko dlatego, że nie rozumiesz rozwiązania. 'mListener' jest implementacją interfejsu' OnCheckChangedListener', który został stworzony przez programistę. Moja odpowiedź sugeruje, że programista utrzymywał odniesienie do ** własnej implementacji ** - 'mListener'. – Shade

+0

Czy zmiana słuchacza jest nieefektywna, jeśli chcesz wielokrotnie używać metody setChecked()? – Ren

0

Chyba stosując odbicie jest jedynym sposobem. Coś takiego:

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

Może działać, dopóki deweloperzy nie zmienią nazwy pól lub, na przykład, nie podniosą metody "isChecked" w hierarchii ... lub nie dokonają kolejnego refaktoryzacji ... Przynajmniej dodaj coś takiego: 'if (Build.VERSION.SDK_INT <= Build.VERSION_CODES .JELLY_BEAN) {/ * do reflection * /} ' – aeracode

+0

Błędnym pomysłem jest zachęcanie do przełamania API i zagłębienia się w elementy wewnętrzne. Wszelkie zmiany w implementacji spowodują awarię aplikacji. – mspanc

8

użyć po prostu setonclickListener, że będzie działa dobrze i jest to bardzo prosta metoda, dzięki :)

+26

Funkcja onClick() nie jest wywoływana, gdy użytkownik przesuwa przełącznik. – James

+1

Rzeczywiście, czyniąc to pozostawiamy bez obsługi, gdy użytkownik przeciągnie przełącznik. –

+0

, a następnie, w jaki sposób otrzymasz wartość isChecked to znaczy prawda lub fałsz? – Abhi

10

Innym możliwym sposobem osiągnięcia tego celu jest za pomocą niestandardowego checkbox:

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

wykorzystanie próbki:

checkBox.setChecked(true,false); 
3

można użyć tej klasy SafeCheckBox jako wyboru:

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); 
    } 
} 
  • Następnie można nazwać: -

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

2

Używanie rozszerzeń Kotlin jest z @Shade odpowiedź:

1

Dla każdego, kto potyka się o to, jeden prostszy sposób to zrobić, to po prostu użyć tagu pole wyboru, a następnie sprawdzić, czy znacznik na jego słuchacza (kod znajduje się Kotlin):

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

Następnie przy dostępie tylko ustawić znacznik true zanim ustaw IsChecked true, jeśli chcesz, aby zignorować zmiany wartość:

checkBox.tag = true 
checkBox.isChecked = true 

można również mapować tag do klucza za pomocą alternatywnej metody setTag który wymaga klucza jeśli byli zaniepokojeni zrozumiałość. Ale jeśli wszystko to jest zawarte w jednej klasie, kilka ciągów komentarzy będzie więcej niż wystarczająco, aby wyjaśnić, co się dzieje.

0

Set null changeListener przed przyciskiem radiowym check. Możesz ustawić detektor ponownie po zaznaczeniu opcji radiowej.

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

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

    } 
}); 
0

Moje rozwiązanie napisany w języku Java na podstawie @Chris odpowiedź:

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 pól i zawsze jeden będzie sprawdzane (jeden musi być wstępnie sprawdzone chociaż). Ustawienie znacznika na prawdziwe bloki na detektoru listenedCheckedChanged.

0

Moja interpretacja, która myślę, że to najprostszy
mogą być pomocne)

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

używać

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

użycie spowoduje setChecked(boolean) funkcja
to wszystko

0

Jest proste rozwiązanie, którego używałem:
Definiowanie niestandardowego słuchacza:

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

Inicjalizacja:

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

Zastosowanie:

checkBoxListener.disable(); 

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

checkBoxListener.enable();