He setOnCheckedChangeListener
implementado para micheckbox
¿Hay alguna manera de llamar?
checkbox.setChecked(false);
sin activar el onCheckedChanged
He setOnCheckedChangeListener
implementado para micheckbox
¿Hay alguna manera de llamar?
checkbox.setChecked(false);
sin activar el onCheckedChanged
Respuestas:
No, no puedes hacerlo. El onCheckedChanged
método se llama directamente desde setChecked
. Lo que puedes hacer es lo siguiente:
mCheck.setOnCheckedChangeListener (null);
mCheck.setChecked (false);
mCheck.setOnCheckedChangeListener (mListener);
Vea la fuente de CheckBox y la implementación 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;
}
}
mListener
? Checkbox
no tiene un captador para suOnCheckChangeListener
mListener
es una implementación de la OnCheckChangedListener
interfaz, que fue creada por el programador. Mi respuesta implica que el programador mantiene una referencia a su propia aplicación - mListener
.
CheckBox
objeto. No diría que es ineficiente.
Agregue este código dentro de OnCheckedChangeListener:
if(!compoundButton.isPressed()) {
return;
}
Esto nos ayudará a descubrir que el estado de la casilla de verificación del clima se modificó mediante programación o por acción del usuario.
Otra posible forma de lograr esto es mediante el uso de un CheckBox personalizado, que le permitirá elegir si desea que se llame al oyente o no:
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();
}
}
Versión de Kotlin, si lo prefiere:
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()
}
}
muestra de uso:
checkBox.setChecked(true,false);
usa simplemente setonclickListener, funcionará bien y este es un método muy simple, gracias :)
Usando las extensiones de Kotlin con la respuesta @Shade:
fun CompoundButton.setCustomChecked(value: Boolean,listener: CompoundButton.OnCheckedChangeListener) {
setOnCheckedChangeListener(null)
isChecked = value
setOnCheckedChangeListener(listener)
}
Para cualquiera que se encuentre con esto, una forma más sencilla de hacerlo es usar una etiqueta en la casilla de verificación y luego verificar esa etiqueta en su escucha (el código está en Kotlin):
checkBox.tag = false
checkBox.setOnCheckedChangeListener{ buttonView, isChecked ->
if(checkBox.tag != true) {
//Do some stuff
} else {
checkBox.tag = false
}
Luego, cuando acceda, simplemente configure la etiqueta en verdadero antes de establecer isChecked en verdadero cuando desee ignorar el cambio de valor:
checkBox.tag = true
checkBox.isChecked = true
También puede asignar la etiqueta a una clave utilizando el método alternativo setTag que requiere una clave si le preocupa la comprensión. Pero si todo está contenido en una sola clase, unas pocas cadenas de comentarios serán más que suficientes para explicar lo que está sucediendo.
Puede usar esta clase SafeCheckBox como su casilla de verificación:
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);
}
}
Entonces puedes llamar: -
setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified
Establezca nulo en changeListener antes de verificar el botón de radio. Puede configurar el oyente nuevamente después de verificar el botón de radio.
radioGroup.setOnCheckedChangeListener(null);
radioGroup.check(R.id.radioButton);
radioGroup.setOnCheckedChangeListener(new
RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, @IdRes int i) {
}
});
Mi interpretación, que creo que es la más fácil,
puede ser útil)
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);
}
}
úsalo
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean on) {
if (((ProgrammableSwitchCompat) compoundButton).isCheckedProgrammatically) {
return;
}
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(true);
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(false);
//...
}
el uso activará la setChecked(boolean)
función
que es todo
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)
}
}
Esta es una solución simple que utilicé:
definir un oyente personalizado:
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;
}
}
Inicializacion:
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (isEnabled()) {
// Your code goes here
}
}
};
myCheckBox.setOnCheckedChangeListener(checkBoxListener);
Uso:
checkBoxListener.disable();
// Some logic based on which you will modify CheckBox state
// Example: myCheckBox.setChecked(true)
checkBoxListener.enable();
Qué tal esto. Intenta usar la etiqueta en la vista
mCheck.setTag("ignore");
mCheck.setChecked(true);
mCheck.setTag(null);
y
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
}
}
});
Usé un ReentrantLock
y lo bloqueo cada vez que configuro 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
}
}
Encontré todas las respuestas anteriores demasiado complicadas. ¿Por qué no simplemente crear su propia bandera con un simple booleano?
Simplemente use un sistema de bandera simple con un booleano. Crear boolean noListener
. Siempre que desee encender / apagar su interruptor sin ejecutar ningún código (en este ejemplo, representado como runListenerCode()
, simplemente configúrelo noListener=true
antes de llamarswitch.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;
}
});
Solución muy simple usando banderas simples. Al final, configuramos noListener=false
una vez más para que nuestro código continúe funcionando. ¡Espero que esto ayude!
¡Prueba que este debería funcionar para ti! ¡Puedes usar esto con firebase también!
¡Para obtener datos de firebase! ¡Utilizar este!
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());
// ...
}
});
Después de eso, cuando el usuario haga algo!
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
}
}
}
});
Realmente no quería tener que pasar al oyente cada vez que configuramos el cambio modificado, ni usarlo enabled
como una forma de determinar si debemos establecer el valor (lo que sucede en el caso de que ya tengamos el interruptor desactivado al establecer el valor ?)
En cambio, estoy usando etiquetas con una identificación y un par de métodos de extensión a los que puede llamar:
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)
}
Ahora puede llamar setCheckedWithoutCallingListener(bool)
y exigirá el uso correcto del oyente.
También puede llamar setChecked(bool)
para despedir al oyente si aún lo necesita
Supongo que usar la reflexión es la única forma. Algo como esto:
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 */}
Mi solución escrita en Java basada en @Chris responde:
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 casillas de verificación y siempre una estará marcada (aunque una debe estar marcada inicialmente). Establecer la etiqueta en bloques verdaderos en el oyenteCheckedChanged.
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();
}