android.widget.Switch - listener di eventi on / off?


229

Vorrei implementare un pulsante switch, android.widget.Switch (disponibile da API v.14).

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

Ma non sono sicuro di come aggiungere un listener di eventi per il pulsante. Dovrebbe essere un ascoltatore "onClick"? E come faccio a sapere se è attivato o meno?


6
OnClick tramite XML funziona davvero, ma solo per "clic" sul pulsante, non per "diapositive".
m02ph3u5,

Risposte:


492

Switch eredita CompoundButtongli attributi, quindi consiglierei 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
    }
});

2
@Johan Nessun problema. Non ti conosco ma vorrei che lo chiamassero OnCheckChangedListener, simile a OnItemSelectedListener, poiché On- Noun - Verb -Listener è una convinzione di denominazione consolidata.
Sam

2
Ma quando metti un frammento, per esempio, quella cosa si accende sempre ogni volta che rivisiti il ​​frammento se imposti l'interruttore su On.
Klutch,

1
@Sam Cosa succede se si desidera cambiare il passaggio allo stato ON o OFF utilizzando il metodo setChcked () e non si desidera eseguire il metodo onCheckedChanged? Ma quando l'utente tocca nuovamente il metodo switch onCheckedChanged viene eseguito ... C'è un modo per farlo?
Deepak Kumar,

2
I pulsanti hanno OnCLick, gli interruttori non hanno OnChange! Team Google ben progettato!
Vassilis,

1
@KZoNE Quello che ho fatto qui è stato usato il listener dei clic per cambiare lo stato e ho passato il passaggio al metodo (nel mio caso chiamata API) e quindi ho usato il metodo setChecked () per cambiare lo stato (come in onFailure / onError nella chiamata API) . Spero che aiuti.
Deepak Kumar,

53

Utilizzare il frammento seguente per aggiungere un passaggio al layout tramite XML:

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

Quindi nel metodo onCreate della tua attività, ottieni un riferimento al tuo switch e imposta 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);
}       

});

3
Questa è una risposta più chiara che ti dà il layout e il codice dietro per abbinare.
AshesToAshes,

come gestire più switchcompat nel singolo listener? Per favore, suggerisci una risposta per questo
Anand Savjani,

22

Per quelli che usano Kotlin, puoi impostare un listener per uno switch (in questo caso con l'ID mySwitch) come segue:

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

isChecked è vero se l'interruttore è attualmente selezionato (ON) e falso altrimenti.


19

Definisci il tuo layout 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> 

Quindi crea un'attività

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

    ****
}

======== Per l' API 14 inferiore utilizzare 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>

Attività

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

2
non dimenticare di controllare buttonView.isPressed ()
JacksOnF1re

5

Il layout del widget Switch è simile a questo.

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

Nella classe Activity, puoi programmare in due modi. Dipende dall'uso che puoi programmare.

Primo modo

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

Secondo modo

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

2

È possibile utilizzare DataBinding e ViewModel per l'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)}"
     />


1
android.widget.Switch non ha attirbute onCheckedChanged. Otterrai un errore: AAPT: errore: attributo android: onCheckedChanged non trovato.
Esaurito il

1

ci sono due modi,

  1. usando la visualizzazione onclick xml Aggiungi Switch in XML come di seguito:

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

Nella classe YourActivity (ad esempio 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 il click listener

Aggiungi Switch in XML come di seguito:

Nella classe YourActivity (ad esempio 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));
                }
            }

        }

    });

0

La mia soluzione, usando a SwitchCompate Kotlin. Nella mia situazione, dovevo reagire a un cambiamento solo se l'utente lo aveva attivato tramite l'interfaccia utente. In effetti, il mio interruttore reagisce a LiveData, e questo ha reso entrambi setOnClickListenere setOnCheckedChangeListenerinutilizzabili. setOnClickListenerin realtà reagisce correttamente all'interazione dell'utente, ma non viene attivato se l'utente trascina il pollice sull'interruttore. setOnCheckedChangeListenerdall'altro lato viene attivato anche se l'interruttore viene attivato a livello di codice (ad esempio da un osservatore). Ora nel mio caso lo switch era presente su due frammenti, e così onRestoreInstanceState avrebbe innescato in alcuni casi lo switch con un vecchio valore sovrascrivendo il valore corretto.

Quindi, ho guardato il codice di SwitchCompat e sono stato in grado di imitare con successo il suo comportamento nel distinguere il clic e il trascinamento e l'ho usato per creare un touchlistener personalizzato che funzioni come dovrebbe. Eccoci qui:

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

Come usarlo:

l'ascoltatore touch effettivo che accetta un lambda con il codice da eseguire:

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

Per completezza, ecco come switchstateappariva l'osservatore per lo stato (se ce l'hai):

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

Il team Android dovrebbe davvero risolvere questo problema. Quello che ho fatto instaurare è nel mio osservatore LiveData, annulla la registrazione di onCheck, eseguo la mia azione, quindi ripristinalo. Questo funziona solo perché le modifiche dell'interfaccia utente avvengono su 1 thread (il thread principale).
Jeremy Jao,

0

A 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"

        }
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.