【问题标题】:android.widget.Switch - on/off event listener?android.widget.Switch - 开/关事件监听器?
【发布时间】:2012-06-30 23:41:48
【问题描述】:

我想实现一个开关按钮,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”监听器吗?我怎么知道它是否“打开”了?

【问题讨论】:

  • 通过 XML 的 OnClick 确实有效 - 但仅适用于按钮上的“点击”,而不适用于“幻灯片”。

标签: android


【解决方案1】:

Switch继承了CompoundButton的属性,所以我推荐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
    }
});

【讨论】:

  • @Johan 没问题。我不了解你,但我希望他们将其命名为 OnCheckChangedListener,类似于 OnItemSelectedListener,因为 On-Noun-Verb-Listener 是一个既定的命名惯例。
  • 但是,例如,当您将 放在片段上时,如果您将开关设置为 On,则无论何时重新访问片段都会触发该东西。
  • @Sam 如果我想使用 setChcked() 方法将开关更改为 ON 或 OFF 状态并且不想执行 onCheckedChanged 方法怎么办?但是当用户再次点击 switch 方法时 onCheckedChanged 被执行......有没有办法做到这一点?
  • 按钮有OnCLick,开关没有OnChange!精心设计的 Google 团队!
  • @KZoNE 我在这里所做的是使用单击侦听器来更改状态并将开关传递给方法(在我的情况下是 API 调用)然后使用 setChecked() 方法来更改状态(例如在 API 调用中的 onFailure/onError 中)。希望对您有所帮助。
【解决方案2】:

使用以下 sn-p 通过 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);
}       

});

【讨论】:

  • 这是一个更清晰的答案,为您提供匹配的布局和代码。
  • 如何在单个监听器中管理多个 switchcompat ?请为此建议答案
【解决方案3】:

对于使用 Kotlin 的用户,您可以为开关(在本例中为 ID mySwitch)设置监听器,如下所示:

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

isChecked 如果当前选中 (ON) 开关,则为 true,否则为 false。

【讨论】:

    【解决方案4】:

    定义您的 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
            }
        }
       *****
    }
    

    【讨论】:

    • 别忘了检查 buttonView.isPressed()
    • @JacksOnF1re 仅捕获用户输入的好方法,无需以编程方式建立
    【解决方案5】:

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

    【讨论】:

    • 这对切换开关没问题,但你如何获得当前状态?
    • @Skovie 布尔状态 = switch_button.isChecked()
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

      您可以将 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)}"
           />
      

      【讨论】:

      • android.widget.Switch 没有 onCheckedChanged 属性。你会得到错误:AAPT: error: attribute android:onCheckedChanged not found.
      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        我的解决方案,使用 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
        })
        

        【讨论】:

        • Android 团队真的应该解决这个问题......我所做的是在我的 LiveData 观察者中,我取消注册 onCheck,执行我的操作,然后将其设置回来。这仅适用于 UI 更改发生在 1 个线程(主线程)上。
        【解决方案10】:

        有两种方法,

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

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

        在 YourActivity 类中(例如 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. 使用点击监听器

        在 XML 中添加 Switch,如下所示:

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

        【讨论】:

          猜你喜欢
          • 2014-01-27
          • 1970-01-01
          • 2023-03-14
          • 2021-08-23
          • 1970-01-01
          • 2014-02-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多