android.widget.Switch - ¿escucha de eventos on / off?

229

Me gustaría implementar un botón de cambio, android.widget.Switch (disponible en 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?

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

Respuestas:

492

Switch hereda CompoundButtonlos atributos, por lo que recomendaría 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
    }
});
Sam
fuente
2
@Johan No hay problema. No sé sobre usted, pero desearía que lo llamaran OnCheckChangedListener, similar a OnItemSelectedListener, ya que On- Noun - Verb -Listener es una convención de nomenclatura establecida.
Sam
2
Pero cuando pones un fragmento, por ejemplo, esa cosa siempre se dispara cada vez que vuelves a visitar el fragmento si activas el interruptor.
klutch
1
@Sam ¿Qué sucede 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, se ejecutan onCheckedChanged ... ¿Hay alguna forma de hacer esto?
deepak kumar
2
Los botones tienen OnCLick, los interruptores no tienen OnChange! ¡Equipo de Google bien diseñado!
Vassilis
1
@KZoNE Lo que hice aquí es usar el escucha de clics para cambiar el estado y pasar el interruptor 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
53

Use el siguiente fragmento para agregar un Switch 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);
}       

});
shridutt kothari
fuente
3
Esta es una respuesta más clara que le brinda el diseño y el código para que coincida.
AshesToAshes
¿Cómo gestionar múltiples switchcompat en el único oyente? Sugiera una respuesta para eso
Anand Savjani, el
22

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

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

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

Faheel
fuente
19

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

    ****
}

======== Por debajo de API 14 use 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
        }
    }
   *****
}
Neferpitou
fuente
2
no olvides comprobar buttonView.isPressed ()
JacksOnF1re
5

El diseño para el 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 pueda codificar.

Primera forma

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");
          }
       }       
     });
   }
}
Abish R
fuente
2

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

Ali hasan
fuente
1
android.widget.Switch no tiene attirbute onCheckedChanged. Obtendrá error: AAPT: error: atributo android: onCheckedChanged no encontrado.
Agotado el
1

hay dos maneras,

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

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

En su clase de actividad (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. utilizando el oyente de clic

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

En su clase de actividad (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));
                }
            }

        }

    });
Mrudul Addipalli
fuente
0

Mi solución, usando a SwitchCompaty 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 una LiveData, y esto hizo que tanto setOnClickListenere setOnCheckedChangeListenerinutilizable. setOnClickListenerde hecho, reacciona correctamente a la interacción del usuario, pero no se activa si el usuario arrastra el pulgar por el interruptor.setOnCheckedChangeListeneren el otro extremo también se activa si el interruptor se alterna mediante programación (por ejemplo, por un observador). Ahora, en mi caso, el conmutador estaba presente en dos fragmentos, y asíRestoreInstanceState activaría en algunos casos el conmutador con un valor anterior sobrescribiendo el valor correcto.

Entonces, miré el código de SwitchCompat y pude imitar su comportamiento con éxito al distinguir hacer clic y arrastrar, y lo usé para crear un escucha táctil 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 switchstatese veía el observador del estado (si lo tiene):

switchstate.observe(this, Observer {
    myswitch.isChecked = it
})
AndrewBloom
fuente
El equipo de Android realmente debería solucionar esto ... Lo que instalé está en mi observador LiveData, anulo el registro en onCheck, hago mi acción y luego lo vuelvo a configurar. Esto solo funciona porque los cambios en la interfaz de usuario ocurren en 1 hilo (el hilo principal).
Jeremy Jao
0

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"

        }
    }
Shadros
fuente