打开/关闭事件监听器?

我想实现一个开关按钮,android.widget.Switch(可从API v.14)。

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

但我不确定如何为按钮添加事件侦听器。它应该是一个“onClick”监听器吗?我怎么知道它是否打开了呢?

347969 次浏览

Switch继承了CompoundButton的属性,所以我建议使用OnCheckedChangeListener . Switch

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

使用下面的代码片段通过XML添加一个Switch到你的布局中:

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

然后在你的Activity的onCreate方法中,获取一个Switch的引用,并设置它的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);
}


});

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

然后创建一个Activity

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


****
}

========对于低于API 14使用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>

活动

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

Switch小部件的布局是这样的。

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

在Activity类中,可以通过两种方式进行编码。这取决于你能编码的用途。

第一个方法

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

第二种方式

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

对于那些使用Kotlin的人,你可以为交换机设置监听器(在这种情况下ID为mySwitch),如下所示:

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

如果当前开关处于检查状态(ON), isChecked为true,否则为false。

你可以使用DataBinding和ViewModel来处理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)}"
/>

我的解决方案,使用SwitchCompat和Kotlin。在我的情况下,只有当用户通过UI触发更改时,我才需要对更改做出反应。事实上,我的开关对LiveData做出反应,这使得setOnClickListenersetOnCheckedChangeListener都不可用。setOnClickListener实际上对用户交互做出正确的反应,但如果用户在开关上拖动拇指,则不会触发它。另一端的setOnCheckedChangeListener如果开关以编程方式切换(例如由观察者)也会被触发。现在在我的例子中,开关存在于两个片段上,因此onRestoreInstanceState在某些情况下会触发开关,用旧值覆盖正确的值。

所以,我看了SwitchCompat的代码,并能够模仿它的行为成功区分点击和拖动,并使用它来构建一个自定义的触摸监听器,因为它应该工作。开始吧:

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

如何使用:

实际的触摸监听器接受lambda代码执行:

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

为了完整起见,状态switchstate(如果你有的话)的观察者是这样的:

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

有两种方法,

  1. 使用XML onclick视图 在XML中添加Switch,如下所示

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

In YourActivity Class (For E.g 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. 使用on click监听器

在XML中添加交换机

在你的activity类中(例如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));
}
}


}


});

在芬兰湾的科特林:

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


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


}
}

2020年9月-程序化回答

你可以通过Switch Widget和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.
}
});