android.widget.Switch: ¿activar/desactivar el detector de eventos?

Me gustaría implementar un botón de cambio, android.widget.Switch (disponible desde API v.14).

<Switch
    android:id="@+id/switch1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Switch" />

Pero no estoy seguro de cómo agregar un detector de eventos para el botón. ¿Debería ser un oyente "onClick"? ¿Y cómo sabría si está "activado" o no?

preguntado el 01 de julio de 12 a las 00:07

OnClick a través de XML realmente funciona, pero solo para "clics" en el botón, no para "diapositivas". -

10 Respuestas

Cambiar hereda CompoundButtonatributos de , por lo que recomendaría el OnCheckedChangeListener

mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        // do something, the isChecked will be
        // true if the switch is in the On position
    }
});

Respondido 19 Abr '15, 07:04

@Johan No hay problema. No sé ustedes, pero me gustaría que lo llamaran OnCheckChangedListener, similar a OnItemSelectedListener, ya que On-Sustantivo-Verb-El oyente es una convención de nomenclatura establecida. - Diana

Pero cuando enciendes un fragmento, por ejemplo, esa cosa siempre se dispara cada vez que vuelves a visitar el fragmento si configuras el interruptor en Encendido. - Lendl Leyba

@Sam ¿Qué pasa si quiero cambiar el interruptor al estado ON u OFF usando el método setChcked() y no quiero ejecutar el método onCheckedChanged? Pero cuando el usuario vuelve a tocar el método de cambio onCheckedChanged se ejecuta ... ¿Hay alguna forma de hacer esto? - Deepak Kumar

Los botones tienen OnCLick, los interruptores no tienen OnChange! ¡Equipo de Google bien diseñado! - Vassilis

@KZoNE Lo que hice aquí fue usar el detector de clics para cambiar el estado y pasar el cambio al método (en mi caso, llamada a la API) y luego usé el método setChecked() para cambiar el estado (como en onFailure/onError en la llamada a la API) . Espero que ayude. - Deepak Kumar

Use el siguiente fragmento para agregar un interruptor a su diseño a través de XML:

<Switch
     android:id="@+id/on_off_switch"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textOff="OFF"
     android:textOn="ON"/>

Luego, en el método onCreate de su Actividad, obtenga una referencia a su Switch y configure su OnCheckedChangeListener:

Switch onOffSwitch = (Switch)  findViewById(R.id.on_off_switch); 
onOffSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    Log.v("Switch State=", ""+isChecked);
}       

});

respondido 01 mar '17, 23:03

Esta es una respuesta más clara que le brinda el diseño y el código detrás para que coincida. - Cenizas a las cenizas

¿Cómo administrar múltiples switchescompat en el único oyente? Por favor sugiera una respuesta para eso - Anand Savjani

Para aquellos que usan Kotlin, puede configurar un oyente para un interruptor (en este caso, con la ID mySwitch) como sigue:

    mySwitch.setOnCheckedChangeListener { _, isChecked ->
         // do whatever you need to do when the switch is toggled here
    }

isChecked es verdadero si el interruptor está activado (ON) y falso en caso contrario.

Respondido 30 Jul 19, 12:07

Defina su diseño XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.neoecosystem.samplex.SwitchActivity">

    <Switch
        android:id="@+id/myswitch"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

</RelativeLayout> 

Luego crea una Actividad

public class SwitchActivity extends ActionBarActivity implements CompoundButton.OnCheckedChangeListener {

    Switch mySwitch = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_switch);


        mySwitch = (Switch) findViewById(R.id.myswitch);
        mySwitch.setOnCheckedChangeListener(this);
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
            // do something when check is selected
        } else {
            //do something when unchecked
        }
    }

    ****
}

======== Para por debajo de API 14 usar SwitchCompat =========

XML

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.neoecosystem.samplex.SwitchActivity">

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/myswitch"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

</RelativeLayout>

Actividad

public class SwitchActivity extends ActionBarActivity implements CompoundButton.OnCheckedChangeListener {

    SwitchCompat mySwitch = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_switch);


        mySwitch = (SwitchCompat) findViewById(R.id.myswitch);
        mySwitch.setOnCheckedChangeListener(this);
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
            // do something when checked is selected
        } else {
            //do something when unchecked
        }
    }
   *****
}

Respondido el 21 de junio de 15 a las 11:06

no olvide verificar buttonView.isPressed() - jacksonfire1re

@JacksOnF1re es una buena manera de capturar solo la entrada del usuario, sin establecimiento programático: Аксенов Владимир

En Kotlin:

        switch_button.setOnCheckedChangeListener { buttonView, isChecked ->
        if (isChecked) {
            // The switch enabled
            text_view.text = "Switch on"

        } else {
            // The switch disabled
            text_view.text = "Switch off"

        }
    }

Respondido el 19 de junio de 20 a las 07:06

esto está bien para el cambio de interruptor, pero ¿cómo se obtiene el estado actual? - Skovie

@Skovie Estado booleano = switch_button.isChecked() - Shadros

El diseño del widget Switch es algo como esto.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <Switch
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="20dp"
        android:gravity="right"
        android:text="All"
        android:textStyle="bold"
        android:textColor="@color/black"
        android:textSize="20dp"
        android:id="@+id/list_toggle" />
</LinearLayout>

En la clase Actividad, puede codificar de dos maneras. Depende del uso que puedas codificar.

Primer camino

public class ActivityClass extends Activity implements CompoundButton.OnCheckedChangeListener {
Switch list_toggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.return_vehicle);

    list_toggle=(Switch)findViewById(R.id.list_toggle);
    list_toggle.setOnCheckedChangeListener(this);
    }
}

public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
    if(isChecked) {
        list_toggle.setText("Only Today's");  //To change the text near to switch
        Log.d("You are :", "Checked");
    }
    else {
        list_toggle.setText("All List");   //To change the text near to switch
        Log.d("You are :", " Not Checked");
    }
}

Segunda forma

public class ActivityClass extends Activity {
Switch list_toggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.return_vehicle);

    list_toggle=(Switch)findViewById(R.id.list_toggle);
    list_toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
       @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
          if(isChecked) {
             list_toggle.setText("Only Today's");  //To change the text near to switch
             Log.d("You are :", "Checked");
          }
          else {
             list_toggle.setText("All List");  //To change the text near to switch
             Log.d("You are :", " Not Checked");
          }
       }       
     });
   }
}

respondido 03 mar '16, 05:03

Puede usar DataBinding y ViewModel para el evento Switch Checked Change

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
                name="viewModel"
                type="com.example.ui.ViewModel" />
    </data>
    <Switch
            android:id="@+id/on_off_switch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onCheckedChanged="@{(button, on) -> viewModel.onCheckedChange(on)}"
     />

respondido 18 nov., 19:16

android.widget.Switch no tiene el atributo onCheckedChanged. Obtendrá un error: AAPT: error: atributo android:onCheckedChanged no encontrado. - Agotado

Septiembre de 2020: respuesta programática

Puede hacerlo mediante programación para Switch Widget y Material Design:

Switch yourSwitchButton = findViewById(R.id.switch_id);

yourSwitchButton.setChecked(true); // true is open, false is close.

yourSwitchButton.setOnCheckedChangeListener((compoundButton, b) -> {
        if (b){
          //open job.
        }  
        else  {
          //close job.
        }
    });

contestado el 21 de mayo de 21 a las 18:05

Mi solución, usando un SwitchCompat y Kotlin. En mi situación, necesitaba reaccionar a un cambio solo si el usuario lo activaba a través de la interfaz de usuario. De hecho, mi interruptor reacciona a un LiveData, y esto hizo que ambos setOnClickListener y setOnCheckedChangeListener inutilizable. setOnClickListener de hecho, reacciona correctamente a la interacción del usuario, pero no se activa si el usuario arrastra el pulgar por el interruptor. setOnCheckedChangeListener en el otro extremo también se activa si el interruptor se activa mediante programación (por ejemplo, por un observador). Ahora, en mi caso, el interruptor estaba presente en dos fragmentos, por lo que onRestoreInstanceState activaría en algunos casos el interruptor con un valor anterior que sobrescribía el valor correcto.

Entonces, miré el código de SwitchCompat y pude imitar su comportamiento con éxito al distinguir el clic y arrastrar y lo usé para construir un touchlistener personalizado que funciona como debería. Aquí vamos:

/**
 * This function calls the lambda function passed with the right value of isChecked
 * when the switch is tapped with single click isChecked is relative to the current position so we pass !isChecked
 * when the switch is dragged instead, the position of the thumb centre where the user leaves the
 * thumb is compared to the middle of the switch, and we assume that left means false, right means true
 * (there is no rtl or vertical switch management)
 * The behaviour is extrapolated from the SwitchCompat source code
 */
class SwitchCompatTouchListener(private val v: SwitchCompat, private val lambda: (Boolean)->Unit) :  View.OnTouchListener {
    companion object {
        private const val TOUCH_MODE_IDLE = 0
        private const val TOUCH_MODE_DOWN = 1
        private const val TOUCH_MODE_DRAGGING = 2
    }

    private val vc = ViewConfiguration.get(v.context)
    private val mScaledTouchSlop = vc.scaledTouchSlop
    private var mTouchMode = 0
    private var mTouchX = 0f
    private var mTouchY = 0f

    /**
     * @return true if (x, y) is within the target area of the switch thumb
     * x,y and rect are in view coordinates, 0,0 is top left of the view
     */
    private fun hitThumb(x: Float, y: Float): Boolean {
        val rect = v.thumbDrawable.bounds
        return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom
    }

    override fun onTouch(view: View, event: MotionEvent): Boolean {
        if (view == v) {
            when (MotionEventCompat.getActionMasked(event)) {
                MotionEvent.ACTION_DOWN -> {
                    val x = event.x
                    val y = event.y
                    if (v.isEnabled && hitThumb(x, y)) {
                        mTouchMode = TOUCH_MODE_DOWN;
                        mTouchX = x;
                        mTouchY = y;
                    }
                }
                MotionEvent.ACTION_MOVE -> {
                    val x = event.x
                    val y = event.y
                    if (mTouchMode == TOUCH_MODE_DOWN &&
                        (abs(x - mTouchX) > mScaledTouchSlop || abs(y - mTouchY) > mScaledTouchSlop)
                    )
                        mTouchMode = TOUCH_MODE_DRAGGING;
                }
                MotionEvent.ACTION_UP,
                MotionEvent.ACTION_CANCEL -> {
                    if (mTouchMode == TOUCH_MODE_DRAGGING) {
                        val r = v.thumbDrawable.bounds
                        if (r.left + r.right < v.width) lambda(false)
                        else lambda(true)
                    } else lambda(!v.isChecked)
                    mTouchMode = TOUCH_MODE_IDLE;
                }
            }
        }
        return v.onTouchEvent(event)
    }
}

Cómo usarlo:

el oyente táctil real que acepta una lambda con el código para ejecutar:

myswitch.setOnTouchListener(
    SwitchCompatTouchListener(myswitch) {
        // here goes all the code for your callback, in my case
        // i called a service which, when successful, in turn would 
        // update my liveData 
        viewModel.sendCommandToMyService(it) 
    }
)

En aras de la exhaustividad, así es como el observador del estado switchstate (si lo tiene) se parecía a:

switchstate.observe(this, Observer {
    myswitch.isChecked = it
})

respondido 19 mar '20, 08:03

El equipo de Android realmente debería arreglar esto... Lo que hice fue instalarlo en mi observador LiveData, cancelé el registro de onCheck, realicé mi acción y luego lo restablecí. Esto solo funciona porque los cambios en la interfaz de usuario ocurren en 1 subproceso (el subproceso principal). - jeremy jao

hay dos maneras,

  1. usando xml onclick view Add Switch en XML como se muestra a continuación:

    <Switch
    android:id="@+id/switch1"
    android:onClick="toggle"/>
    

En YourActivity Class (por ejemplo, MainActivity.java)

    Switch toggle; //outside oncreate
    toggle =(Switch) findViewById(R.id.switch1); // inside oncreate

    public void toggle(View view) //outside oncreate
    {
        if( toggle.isChecked() ){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                start.setBackgroundColor(getColor(R.color.gold));
                stop.setBackgroundColor(getColor(R.color.white));
            }
        }
        else
        {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                stop.setBackgroundColor(getColor(R.color.gold));
                start.setBackgroundColor(getColor(R.color.white));
            }
        }
    }
  1. usando on click listener

Agregue Switch en XML como se muestra a continuación:

En YourActivity Class (por ejemplo, MainActivity.java)

    Switch toggle; // outside oncreate
    toggle =(Switch) findViewById(R.id.switch1);  // inside oncreate


    toggle.setOnClickListener(new View.OnClickListener() {   // inside oncreate
        @Override
        public void onClick(View view) {

            if( toggle.isChecked() ){
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    start.setBackgroundColor(getColor(R.color.gold));
                }
            }
            else
            {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    stop.setBackgroundColor(getColor(R.color.gold));
                }
            }

        }

    });

contestado el 17 de mayo de 20 a las 18:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.