android.widget.Switch - detektor zdarzeń on / off?

229

Chciałbym wdrożyć przycisk przełącznika android.widget.Switch (dostępny z API v.14).

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

Ale nie jestem pewien, jak dodać detektor zdarzeń dla przycisku. Czy powinien to być odbiornik „onClick”? A skąd mam wiedzieć, czy jest włączony, czy nie?

Johan
źródło
6
OnClick przez XML faktycznie działa - ale tylko dla „kliknięć” przycisku, a nie dla „slajdów”.
m02ph3u5

Odpowiedzi:

492

Przełącz CompoundButtonatrybuty dziedziczy , więc poleciłbym 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
źródło
2
@Johan Bez problemu. Nie wiem o tobie, ale chciałbym, żeby nazwali go OnCheckChangedListener, podobnie jak OnItemSelectedListener, ponieważ On- Noun - Verb -Listener to ustalone konwertowanie nazw.
Sam
2
Ale na przykład po włożeniu fragmentu ten element zawsze się uruchamia za każdym razem, gdy ponownie odwiedzasz fragment, jeśli ustawisz przełącznik w pozycji Wł.
klutch
1
@Sam Co zrobić, jeśli chcę zmienić przełącznik w stan ON lub OFF za pomocą metody setChcked () i nie chcę wykonywać metody onCheckedChanged? Ale kiedy użytkownik ponownie dotknie metody przełączania on CheckedChanged, zostanie wykonany ... Czy jest na to sposób?
deepak kumar
2
Przyciski mają OnCLick, przełączniki nie mają OnChange! Dobrze zaprojektowany zespół Google!
Vassilis
1
@KZoNE To, co zrobiłem tutaj, służy do nasłuchiwania kliknięć w celu zmiany stanu i przekazania metody do metody (w moim przypadku wywołanie interfejsu API), a następnie do zmiany stanu posłużyła się metodą setChecked () (jak w przypadku onFailure / onError w wywołaniu API) . Mam nadzieję, że to pomaga.
deepak kumar
53

Użyj następującego fragmentu kodu, aby dodać Switch do swojego układu poprzez XML:

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

Następnie w metodzie onCreate działania uzyskaj odwołanie do przełącznika i ustaw jego 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
źródło
3
Jest to bardziej jednoznaczna odpowiedź, podająca układ i kod, który należy dopasować.
AshesToAshes,
jak zarządzać wieloma switchcompat w jednym odbiorniku? Proszę zasugerować odpowiedź na to pytanie
Anand Savjani,
22

Dla tych, którzy używają Kotlin, możesz ustawić detektor dla przełącznika (w tym przypadku posiadającego identyfikator mySwitch) w następujący sposób:

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

isChecked ma wartość true, jeśli przełącznik jest obecnie zaznaczony (ON), a false w przeciwnym razie.

Faheel
źródło
19

Zdefiniuj swój układ 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> 

Następnie utwórz działanie

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

    ****
}

======== Dla poniżej API 14 użyj 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>

Czynność

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
źródło
2
nie zapomnij sprawdzić buttonView.isPressed ()
JacksOnF1re
5

Układ widgetu Switch jest mniej więcej taki.

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

W klasie Activity możesz kodować na dwa sposoby. Zależy od sposobu, w jaki możesz kodować.

Pierwszy sposób

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

Drugi sposób

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
źródło
2

Możesz użyć DataBinding i ViewModel dla zdarzenia Change Checked Check

<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
źródło
1
android.widget.Switch nie ma onCheckedChanged attirbute. Pojawi się błąd: AAPT: błąd: atrybut android: onCheckedChanged nie znaleziono.
Wyprzedane
1

są dwa sposoby

  1. za pomocą widoku XML onclick Dodaj przełącznik w XML, jak poniżej:

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

W klasie YourActivity (na przykład 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. za pomocą nasłuchiwania kliknięcia

Dodaj Switch w XML, jak poniżej:

W klasie YourActivity (na przykład 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
źródło
0

Moje rozwiązanie, używając a SwitchCompati Kotlin. W mojej sytuacji musiałem zareagować na zmianę tylko wtedy, gdy użytkownik wywołał ją za pomocą interfejsu użytkownika. W rzeczywistości, mój przełącznik reaguje na LiveData, i to zarówno wykonane setOnClickListeneri setOnCheckedChangeListenerbezużyteczny. setOnClickListenerw rzeczywistości prawidłowo reaguje na interakcję użytkownika, ale nie jest uruchamiany, jeśli użytkownik przeciągnie kciukiem po przełączniku.setOnCheckedChangeListenerna drugim końcu jest wyzwalany także wtedy, gdy przełącznik jest programowo przełączany (na przykład przez obserwatora). Teraz w moim przypadku przełącznik był obecny na dwóch fragmentach, a więc onRestoreInstanceState w niektórych przypadkach wyzwalałby przełącznik ze starą wartością zastępującą poprawną wartość.

Więc spojrzałem na kod SwitchCompat i byłem w stanie naśladować jego zachowanie, rozróżniając kliknięcie i przeciągnięcie, i użyłem go do zbudowania niestandardowego listera dotykowego, który działa tak, jak powinien. No to ruszamy:

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

Jak tego użyć:

rzeczywisty detektor dotyku, który akceptuje lambda z kodem do wykonania:

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

Dla kompletności tak wyglądał obserwator stanu switchstate(jeśli go masz):

switchstate.observe(this, Observer {
    myswitch.isChecked = it
})
AndrewBloom
źródło
Zespół Androida naprawdę powinien to naprawić ... To, co zrobiłem, jest w moim obserwatorze LiveData, wyrejestrowuję onCheck, wykonuję swoje działanie, a następnie ustawiam go z powrotem. Działa to tylko dlatego, że zmiany interfejsu użytkownika zachodzą w 1 wątku (głównym wątku).
Jeremy Jao
0

W Kotlinie:

        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
źródło