SwitchCompat및 Kotlin을 사용하는 내 솔루션 . 내 상황에서 사용자가 UI를 통해 변경 한 경우에만 변경에 반응해야했습니다. 사실, 내 스위치 A에 반응 LiveData하고,이 두 만든 setOnClickListener및 setOnCheckedChangeListener사용할 수 있습니다. 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)
}
}
사용 방법:
실행할 코드가있는 람다를 받아들이는 실제 터치 리스너 :
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
})