Ich habe setOnCheckedChangeListener
für meine implementiertcheckbox
Gibt es einen Weg, den ich anrufen kann?
checkbox.setChecked(false);
ohne die auszulösen onCheckedChanged
Ich habe setOnCheckedChangeListener
für meine implementiertcheckbox
Gibt es einen Weg, den ich anrufen kann?
checkbox.setChecked(false);
ohne die auszulösen onCheckedChanged
Antworten:
Nein, das kannst du nicht. Die onCheckedChanged
Methode wird direkt von aufgerufen setChecked
. Was Sie tun können, ist Folgendes:
mCheck.setOnCheckedChangeListener (null);
mCheck.setChecked (false);
mCheck.setOnCheckedChangeListener (mListener);
Siehe die Quelle von CheckBox und die Implementierung von 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;
}
}
mListener
? Checkbox
hat keinen Getter für seineOnCheckChangeListener
mListener
ist eine Implementierung der OnCheckChangedListener
Schnittstelle, die vom Programmierer erstellt wurde. Meine Antwort impliziert, dass der Programmierer einen Verweis auf seine eigene Implementierung beibehalten hat - mListener
.
CheckBox
Objekt. Ich würde nicht sagen, dass das ineffizient ist.
Fügen Sie diesen Code in OnCheckedChangeListener hinzu:
if(!compoundButton.isPressed()) {
return;
}
Dies hilft uns herauszufinden, ob der Status der Wetterkontrollbox programmgesteuert oder durch Benutzeraktion geändert wurde.
Eine andere Möglichkeit, dies zu erreichen, ist die Verwendung einer benutzerdefinierten CheckBox, mit der Sie auswählen können, ob der Listener aufgerufen werden soll oder nicht:
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-Version, wenn Sie es vorziehen:
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()
}
}
Beispielnutzung:
checkBox.setChecked(true,false);
Sie verwenden einfach setonclickListener, es wird gut funktionieren und dies ist eine sehr einfache Methode, danke :)
Verwenden von Kotlins Erweiterungen mit @Shade Antwort:
fun CompoundButton.setCustomChecked(value: Boolean,listener: CompoundButton.OnCheckedChangeListener) {
setOnCheckedChangeListener(null)
isChecked = value
setOnCheckedChangeListener(listener)
}
Für alle, die darauf stoßen, besteht eine einfachere Möglichkeit darin, einfach ein Tag im Kontrollkästchen zu verwenden und dieses Tag dann im Listener zu aktivieren (Code befindet sich in Kotlin):
checkBox.tag = false
checkBox.setOnCheckedChangeListener{ buttonView, isChecked ->
if(checkBox.tag != true) {
//Do some stuff
} else {
checkBox.tag = false
}
Setzen Sie dann beim Zugriff einfach das Tag auf true, bevor Sie isChecked auf true setzen, wenn Sie die Wertänderung ignorieren möchten:
checkBox.tag = true
checkBox.isChecked = true
Sie können das Tag auch einem Schlüssel zuordnen, indem Sie die alternative setTag-Methode verwenden, für die ein Schlüssel erforderlich ist, wenn Sie Bedenken hinsichtlich der Verständlichkeit haben. Aber wenn alles in einer einzelnen Klasse enthalten ist, sind ein paar Kommentarzeichenfolgen mehr als genug, um zu erklären, was passiert.
Sie können diese SafeCheckBox-Klasse als Kontrollkästchen verwenden:
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);
}
}
Dann könnten Sie anrufen: -
setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified
Setzen Sie null auf changeListener, bevor Sie das Optionsfeld aktivieren. Sie können den Listener erneut einstellen, nachdem Sie das Optionsfeld aktiviert haben.
radioGroup.setOnCheckedChangeListener(null);
radioGroup.check(R.id.radioButton);
radioGroup.setOnCheckedChangeListener(new
RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, @IdRes int i) {
}
});
Meine Interpretation, die ich für die einfachste halte,
kann hilfreich sein.
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);
}
}
benutze es
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean on) {
if (((ProgrammableSwitchCompat) compoundButton).isCheckedProgrammatically) {
return;
}
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(true);
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(false);
//...
}
Mit use wird eine setChecked(boolean)
Funktion ausgelöst
, die alles ist
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)
}
}
Dies ist eine einfache Lösung, die ich verwendet habe:
Definieren Sie einen benutzerdefinierten Listener:
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;
}
}
Initialisierung:
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (isEnabled()) {
// Your code goes here
}
}
};
myCheckBox.setOnCheckedChangeListener(checkBoxListener);
Verwendung:
checkBoxListener.disable();
// Some logic based on which you will modify CheckBox state
// Example: myCheckBox.setChecked(true)
checkBoxListener.enable();
Wie wäre es damit. Versuchen Sie, Tag in View zu verwenden
mCheck.setTag("ignore");
mCheck.setChecked(true);
mCheck.setTag(null);
und
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
}
}
});
Ich habe a verwendet ReentrantLock
und es gesperrt, wenn ich Folgendes einstelle 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
}
}
Ich fand alle obigen Antworten viel zu kompliziert. Warum erstellen Sie nicht einfach Ihre eigene Flagge mit einem einfachen Booleschen Wert?
Verwenden Sie einfach ein einfaches Flag-System mit einem Booleschen Wert. Erstellen boolean noListener
. Wann immer Sie Ihren Schalter ein- und ausschalten möchten, ohne Code auszuführen (in diesem Beispiel dargestellt als runListenerCode()
, einfach noListener=true
vor dem Aufruf festgelegtswitch.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;
}
});
Sehr einfache Lösung mit einfachen Flags. Am Ende setzen wir noListener=false
noch einmal, damit unser Code weiter funktioniert. Hoffe das hilft!
Versuchen Sie dieses sollte für Sie arbeiten! Sie können dies auch mit Firebase verwenden!
Um Firebase-Daten zu erhalten! Benutze das!
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());
// ...
}
});
Danach, wenn Benutzer etwas tun!
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
}
}
}
});
Ich wollte nicht wirklich den Listener jedes Mal übergeben müssen, wenn wir das Kontrollkästchen geändert oder verwendet haben enabled
, um zu bestimmen, ob wir den Wert einstellen sollen (was passiert, wenn der Schalter bereits beim Einstellen des Werts deaktiviert ist ?)
Stattdessen verwende ich Tags mit einer ID und einigen Erweiterungsmethoden, die Sie aufrufen können:
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)
}
Jetzt können Sie anrufen setCheckedWithoutCallingListener(bool)
und die korrekte Verwendung des Listeners erzwingen.
Sie können auch weiterhin anrufen setChecked(bool)
, um den Listener zu feuern, wenn Sie ihn noch benötigen
Ich denke, Reflexion ist der einzige Weg. Etwas wie das:
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();
}
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
Meine in Java geschriebene Lösung basiert auf der Antwort von @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 Kontrollkästchen und immer eines wird aktiviert (eines muss jedoch zunächst aktiviert werden). Setzen des Tags auf true blockiert onCheckedChanged Listener.
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();
}