Search code examples
androidkotlindata-bindingtouchlistener

How to detect double-tap with databinding in Kotlin?


I am trying to detect double tap on an ImageView by using databinding.

I have set up my layout XML this way:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="myViewModel"
            type="com.virtualsheetmusic.vsheetmusic.viewer.myViewModel" />

    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/viewContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

         <ImageView
            android:id="@+id/drawingCanvas"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:srcCompat="@drawable/myrect"
            android:visibility="visible"
            app:onTouch="@{musicViewerViewModel.touchListener}"
            android:contentDescription="Canvas for anotations, gestures, etc" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

And this is my binding adapter:

@BindingAdapter("app:onTouch")
fun setXMLTouchListener(layout : ImageView , listener : View.OnTouchListener)
{
    layout.setOnTouchListener(listener)
}

Finally, here is my receiver method in myViewModel:

val touchListener = View.OnTouchListener { v, detect ->

   //Code to detect double-tap here??

   return@OnTouchListener true
}

I have tried several different solutions looking around but I couldn't find one to be implemented in the method above.


Solution

  • There is a little hack for detecting a double tap by measuring the time between the fist tap and the second one.

    In ViewModel class:

    // This is max duration between first and second taps 
    // which is a relative value, You can manipulate it.
    companion object {
        private const val DOUBLE_CLICK_DELTA: Long = 300  // Millisec
    }
    
    // a variable for tracking the tap timing:
    var lastClickTime: Long = 0
    
    @SuppressLint("ClickableViewAccessibility")
    val touchListener = View.OnTouchListener { v, detect ->
    
        if (detect.action == MotionEvent.ACTION_DOWN) { // Avoid UP event
            // Detecting double-tap:
            val clickTime = System.currentTimeMillis()
            if (clickTime - lastClickTime < DOUBLE_CLICK_DELTA) {
                Toast.makeText(application, "Double tap", Toast.LENGTH_SHORT).show()
            }
            lastClickTime = clickTime
        }
    
        return@OnTouchListener true 
    }