简体   繁体   English

如何监听 SwitchCompat 小部件中的状态变化?

[英]How to listen for state change in SwitchCompat widget?

How to listen for SwitchCompat widget clicks?如何监听 SwitchCompat 小部件点击? I want to execute a few statements when the Switch is toggled.我想在切换开关时执行一些语句。

Looking for an equivalent of寻找相当于

button.setOnClickListener(new View.OnClickListener() {
    @Override
        public void onClick(View view) {
        //Do something
    }
});
static Boolean isTouched = false;

switchButton.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                isTouched = true;
                return false;
            }
        });

switchButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
    {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if (isTouched) {
                isTouched = false;
                if (isChecked) {
                }
                else {
                }
            }
        }
    });

Try this!尝试这个!

you need only this(the setOnTouchListener is unnecessary):你只需要这个(setOnTouchListener 是不必要的):

switchButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
    {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {

                if (isChecked) {
                     //if 'isChecked' is true do whatever you need...
                }
                else {
                }
            }
        }
    });

With Butterknife SwitchCompat state change随着 Butterknife SwitchCompat 状态改变

  @OnCheckedChanged(R.id.switchCompat)
  public void onCheckedChanged(SwitchCompat switchCompat, boolean isChecked) {
    Log.i("skh", "check:" + isChecked);

    if (isChecked) {
        // Log.i("skh","check:"+isChecked);
    } else {

    }
}

Now it's possible to check with isPressed method within the same callback.现在可以在同一个回调中使用 isPressed 方法进行检查。

    switchCompat.setOnCheckedChangeListener { buttonView, isChecked ->
        if (buttonView?.isPressed == true) {
            // todo
        } else {
            
        }
    }

I had the same problem Slay explains on the comment to the accepted answer.我有同样的问题 Slay 在对已接受答案的评论中解释。 Here the solution!解决办法来了!

My solution, using a SwitchCompat and Kotlin.我的解决方案,使用SwitchCompat和 Kotlin。 In my situation, i needed to react to a change only if the user triggered it through the UI.在我的情况下,只有当用户通过 UI 触发更改时,我才需要对更改做出反应。 In fact, my switch reacts to a LiveData , and this made both setOnClickListener and setOnCheckedChangeListener unusable.事实上,我的开关对LiveData做出反应,这使得setOnClickListenersetOnCheckedChangeListener无法使用。 setOnClickListener in fact reacts correctly to user interaction, but it's not triggered if the user drags the thumb across the switch. setOnClickListener实际上对用户交互做出正确反应,但如果用户将拇指拖过开关,则不会触发它。 setOnCheckedChangeListener on the other end is triggered also if the switch is toggled programmatically (for example by an observer).如果以编程方式切换开关(例如由观察者),另一端的setOnCheckedChangeListener也会被触发。 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.现在,在我的情况下,开关出现在两个片段上,因此 onRestoreInstanceState 在某些情况下会触发开关,旧值覆盖正确的值。

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.所以,我查看了 SwitchCompat 的代码,并且能够成功地模仿它在区分点击和拖动方面的行为,并使用它来构建一个可以正常工作的自定义触摸侦听器。 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:实际的触摸侦听器,它接受带有要执行的代码的 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) 
    }
)

For the sake of completeness, this is how the observer for the state switchstate (if you have it) looked like:为了完整起见,这就是状态switchstate的观察者(如果有的话)的样子:

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

Actually, you just need this:其实你只需要这个:

if (yourSwitchButton.isChecked()) {
//do what you want here
} else{
//do what you want here
}

That's all!就这样!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM