A SwitchCompatve Kotlin kullanarak çözümüm . Benim durumumda, bir değişime yalnızca kullanıcı kullanıcı arayüzü aracılığıyla tetiklediğinde tepki vermeliydim. Aslında, benim anahtar bir karşı tepki verir LiveDatave bu hem yapılmış setOnClickListenerve setOnCheckedChangeListenerkullanışsız. setOnClickListeneraslında kullanıcı etkileşimine doğru tepki verir, ancak kullanıcı başparmağı anahtar boyunca sürüklerse tetiklenmez. setOnCheckedChangeListenerdiğer uçta da anahtar programlı olarak değiştirilirse (örneğin bir gözlemci tarafından) tetiklenir. Şimdi benim durumumda anahtar iki parça üzerinde mevcuttu ve bu yüzden onRestoreInstanceState bazı durumlarda eski değeri olan anahtarın doğru değerin üzerine yazılmasını tetikleyecektir.
Bu yüzden, SwitchCompat koduna baktım ve tıklama ve sürüklemeyi ayırt etme davranışını başarıyla taklit edebildim ve gerektiği gibi çalışan özel bir dokunmatik liste oluşturmak için kullandım. İşte başlıyoruz:
/**
* 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)
}
}
Bu nasıl kullanılır:
yürütmek için kodlu bir lambda kabul eden gerçek dokunmatik dinleyici:
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)
}
)
Bütünlük uğruna, devletin gözlemcisi switchstate(eğer varsa) şöyle görünüyordu:
switchstate.observe(this, Observer {
myswitch.isChecked = it
})