android.widget.Switch - on/off event listener?

前端 未结 11 1477
庸人自扰
庸人自扰 2020-12-02 04:56

I would like to implement a switch button, android.widget.Switch (available from API v.14).



        
相关标签:
11条回答
  • 2020-12-02 05:43

    For those using Kotlin, you can set a listener for a switch (in this case having the ID mySwitch) as follows:

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

    isChecked is true if the switch is currently checked (ON), and false otherwise.

    0 讨论(0)
  • 2020-12-02 05:44

    Define your XML layout:

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

    Then create an 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
            }
        }
    
        ****
    }
    

    ======== For below 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>
    

    Activity

    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
            }
        }
       *****
    }
    
    0 讨论(0)
  • 2020-12-02 05:45

    You can use DataBinding and ViewModel for Switch Checked Change event

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

    0 讨论(0)
  • 2020-12-02 05:46

    My solution, using a SwitchCompat and Kotlin. In my situation, i needed to react to a change only if the user triggered it through the UI. In fact, my switch reacts to a LiveData, and this made both setOnClickListener and setOnCheckedChangeListener unusable. setOnClickListener in fact reacts correctly to user interaction, but it's not triggered if the user drags the thumb across the switch. setOnCheckedChangeListener on the other end is triggered also if the switch is toggled programmatically (for example by an observer). Now in my case the switch was present on two fragments, and so onRestoreInstanceState would trigger in some cases the switch with an old value overwriting the correct value.

    So, i looked at the code of SwitchCompat, and was able to mimic it's behaviour successfully in distinguishing click and drag and used that to build a custom touchlistener that works as it should. Here we go:

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

    How to use it:

    the actual touch listener that accepts a lambda with the code to execute:

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

    For the sake of completeness, this is how the observer for the state switchstate (if you have it) looked like:

    switchstate.observe(this, Observer {
        myswitch.isChecked = it
    })
    
    0 讨论(0)
  • 2020-12-02 05:47

    Switch inherits CompoundButton's attributes, so I would recommend the 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
        }
    });
    
    0 讨论(0)
提交回复
热议问题