Skip to content

Instantly share code, notes, and snippets.

@jsh-me
Last active October 12, 2021 12:21
Show Gist options
  • Save jsh-me/bede73802fa624f4196889bb23d43f38 to your computer and use it in GitHub Desktop.
Save jsh-me/bede73802fa624f4196889bb23d43f38 to your computer and use it in GitHub Desktop.
Implement SingleClick and LongClick using onTouchListener
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.BehaviorSubject
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ViewTouchEventDetector @Inject constructor() {
private var elapsedSecond = 0
private lateinit var targetView: View
private lateinit var touchTimer: Timer
private val compositeDisposable = CompositeDisposable()
private val singleClickDetector = BehaviorSubject.create<Unit>()
private val longClickDetector = BehaviorSubject.create<Unit>()
private val touchUpEventDetector = BehaviorSubject.create<Unit>()
@SuppressLint("ClickableViewAccessibility")
fun bindTargetViewEvent(
view: View,
) {
targetView = view
targetView.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
startTimer()
true
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL,
-> {
cancelTimer()
true
}
else -> true
}
}
}
fun setViewClickEvent(
touchUpListener: () -> Unit,
singleClickListener: () -> Unit,
longClickListener: () -> Unit,
) {
clickEventDetector(
singleClickListener,
longClickListener,
touchUpListener
)
}
fun clearClickEvent() {
targetView.setOnTouchListener(null)
}
private fun clickEventDetector(singleClickListener: () -> Unit, longClickListener: () -> Unit, touchUpListener: () -> Unit) {
initState {
touchUpListener()
}
compositeDisposable += singleClickDetector
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
singleClickListener()
}
compositeDisposable += longClickDetector
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
longClickListener()
}
compositeDisposable += Observable.zip(
longClickDetector,
touchUpEventDetector
) { _, _ -> }
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
touchUpListener()
}
}
private fun initState(init: () -> Unit) = init()
private fun startTimer() {
touchTimer = kotlin.concurrent.timer(period = MILLIS_OF_SECOND) {
elapsedSecond++
checkUserLongPressed()
}
}
private fun checkUserLongPressed() {
if (elapsedSecond >= LONG_PRESSED_TIME) {
longClickDetector.onNext(Unit)
}
}
private fun cancelTimer() {
touchTimer.cancel()
touchUpEventDetector.onNext(Unit)
checkUserSinglePressed()
elapsedSecond = 0
}
private fun checkUserSinglePressed() {
if (elapsedSecond < LONG_PRESSED_TIME) {
singleClickDetector.onNext(Unit)
}
}
fun clear() {
compositeDisposable.clear()
}
companion object {
/** Long Press 판단 기준 시간 */
private const val LONG_PRESSED_TIME = 2L
private const val MILLIS_OF_SECOND = 1000L
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment