Skip to content

Instantly share code, notes, and snippets.

@srix55
Last active October 16, 2023 11:43
Show Gist options
  • Save srix55/ec64d2f6a371c80bbbc4 to your computer and use it in GitHub Desktop.
Save srix55/ec64d2f6a371c80bbbc4 to your computer and use it in GitHub Desktop.
Simple double-click listener that can be used like the way OnClickListener is used on a view in Android
import android.os.SystemClock;
import android.view.View;
import android.view.View.OnClickListener;
/**
* A simple double-click listener
* Usage:
* // Scenario 1: Setting double click listener for myView
* myView.setOnClickListener(new DoubleClickListener() {
*
* @Override
* public void onDoubleClick() {
* // double-click code that is executed if the user double-taps
* // within a span of 200ms (default).
* }
* });
*
* // Scenario 2: Setting double click listener for myView, specifying a custom double-click span time
* myView.setOnClickListener(new DoubleClickListener(500) {
*
* @Override
* public void onDoubleClick() {
* // double-click code that is executed if the user double-taps
* // within a span of 500ms (default).
* }
* });
*
* @author Srikanth Venkatesh
* @version 1.0
* @since 2014-09-15
*/
public abstract class DoubleClickListener implements OnClickListener {
// The time in which the second tap should be done in order to qualify as
// a double click
private static final long DEFAULT_QUALIFICATION_SPAN = 200;
private long doubleClickQualificationSpanInMillis;
private long timestampLastClick;
public DoubleClickListener() {
doubleClickQualificationSpanInMillis = DEFAULT_QUALIFICATION_SPAN;
timestampLastClick = 0;
}
public DoubleClickListener(long doubleClickQualificationSpanInMillis) {
this.doubleClickQualificationSpanInMillis = doubleClickQualificationSpanInMillis;
timestampLastClick = 0;
}
@Override
public void onClick(View v) {
if((SystemClock.elapsedRealtime() - timestampLastClick) < doubleClickQualificationSpanInMillis) {
onDoubleClick();
}
timestampLastClick = SystemClock.elapsedRealtime();
}
public abstract void onDoubleClick();
}
@Tsabary
Copy link

Tsabary commented May 2, 2019

Works perfectly! Thank you.

@paintedpotato
Copy link

Yes, thank you..

@Brokoth
Copy link

Brokoth commented Jul 6, 2019

Thank you so much for this. took 2 seconds to add to my project.

@mikelis135
Copy link

doesn't work for me..trying to use in a fragment adapter

@gulsicka
Copy link

Worked perfectly for me. Thankyou :')

@trietbui85
Copy link

Could you add a Kotlin version of DoubleClickListener too? Thanks.

@sagarnayak
Copy link

kotlin version -

	import android.view.View

	class DoubleClickListener(
		private val doubleClickTimeLimitMills: Long = 1000,
		private val callback: Callback
	) :
		View.OnClickListener {
		private var lastClicked: Long = -1L

		override fun onClick(v: View?) {
			lastClicked = when {
				lastClicked == -1L -> {
					System.currentTimeMillis()
				}
				isDoubleClicked() -> {
					callback.doubleClicked()
					-1L
				}
				else -> {
					System.currentTimeMillis()
				}
			}
		}

		private fun getTimeDiff(from: Long, to: Long): Long {
			return to - from
		}

		private fun isDoubleClicked(): Boolean {
			return getTimeDiff(
				lastClicked,
				System.currentTimeMillis()
			) <= doubleClickTimeLimitMills
		}

		interface Callback {
			fun doubleClicked()
		}
	}

Impl -

    binding.imageView.setOnClickListener(
        DoubleClickListener(
            callback = object : DoubleClickListener.Callback {
                override fun doubleClicked() {
                
                }
            }
        )
    )

@trietbui85
Copy link

Thanks @sagarnayak for your script :)

@Doomsdayrs
Copy link

Doomsdayrs commented Aug 18, 2020

Kotlin version, Smaller with an extension function

/**
 * Is an onClickListener that handles doubleClickListener
 *
 * @param doubleClickQualificationTime The time in which the second tap should be done
 * in order to qualify as a double click. Time in MS
 */
abstract class DoubleClickListener(
		private val doubleClickQualificationTime: Long = 200
) : View.OnClickListener {

	private var timestampLastClick = 0L

	/***/
	override fun onClick(v: View) {
		if ((elapsedRealtime() - timestampLastClick) < doubleClickQualificationTime)
			onDoubleClick(v)
		timestampLastClick = elapsedRealtime();
	}

	/** When the view is double clicked */
	abstract fun onDoubleClick(v: View)
}

/**
 * Creates a [DoubleClickListener] and applies it to a view
 */
inline fun View.setOnDoubleClickListener(
		crossinline onDoubleClick: (View) -> Unit
) {
	setOnClickListener(object : DoubleClickListener() {
		override fun onDoubleClick(v: View) {
			onDoubleClick(v)
		}
	})
}

@Duna
Copy link

Duna commented Dec 30, 2020

How about detecting both: simple and double clicks?

public abstract static class DoubleClickListener implements View.OnClickListener {
        private static final long DEFAULT_QUALIFICATION_SPAN = 200;
        private long delta;
        private long deltaClick;

        public DoubleClickListener() {
            delta = DEFAULT_QUALIFICATION_SPAN;
            deltaClick = 0;
        }

        @Override
        public void onClick(View v) {
            han.removeCallbacksAndMessages(null);
            han.postDelayed(new Runnable() {
                @Override
                public void run() {
                    onSingleClick();
                }
            }, delta);
            if ((SystemClock.elapsedRealtime() - deltaClick) < delta) {
                han.removeCallbacksAndMessages(null);
                onDoubleClick();
            }
            deltaClick = SystemClock.elapsedRealtime();
        }

        public abstract void onDoubleClick();

        public abstract void onSingleClick();
    }

and for Kotlin lovers 😍

abstract class DoubleClickListener : View.OnClickListener {
        private val delta: Long
        private var deltaClick: Long
        override fun onClick(v: View) {
            han.removeCallbacksAndMessages(null)
            han.postDelayed({ onSingleClick() }, delta)
            if (SystemClock.elapsedRealtime() - deltaClick < delta) {
                han.removeCallbacksAndMessages(null)
                onDoubleClick()
            }
            deltaClick = SystemClock.elapsedRealtime()
        }

        abstract fun onDoubleClick()
        abstract fun onSingleClick()

        companion object {
            private const val DEFAULT_QUALIFICATION_SPAN: Long = 200
        }

        init {
            delta = DEFAULT_QUALIFICATION_SPAN
            deltaClick = 0
        }
    }

@andreadibartolo
Copy link

Hi @srix55, is there any way to detect more than 2 taps? Maybe by parameterizing the quantity itself, whether it is 2 or 10.

@yahyalmh
Copy link

How about detecting both: simple and double clicks?

public abstract static class DoubleClickListener implements View.OnClickListener {
        private static final long DEFAULT_QUALIFICATION_SPAN = 200;
        private long delta;
        private long deltaClick;

        public DoubleClickListener() {
            delta = DEFAULT_QUALIFICATION_SPAN;
            deltaClick = 0;
        }

        @Override
        public void onClick(View v) {
            han.removeCallbacksAndMessages(null);
            han.postDelayed(new Runnable() {
                @Override
                public void run() {
                    onSingleClick();
                }
            }, delta);
            if ((SystemClock.elapsedRealtime() - deltaClick) < delta) {
                han.removeCallbacksAndMessages(null);
                onDoubleClick();
            }
            deltaClick = SystemClock.elapsedRealtime();
        }

        public abstract void onDoubleClick();

        public abstract void onSingleClick();
    }

and for Kotlin lovers

abstract class DoubleClickListener : View.OnClickListener {
        private val delta: Long
        private var deltaClick: Long
        override fun onClick(v: View) {
            han.removeCallbacksAndMessages(null)
            han.postDelayed({ onSingleClick() }, delta)
            if (SystemClock.elapsedRealtime() - deltaClick < delta) {
                han.removeCallbacksAndMessages(null)
                onDoubleClick()
            }
            deltaClick = SystemClock.elapsedRealtime()
        }

        abstract fun onDoubleClick()
        abstract fun onSingleClick()

        companion object {
            private const val DEFAULT_QUALIFICATION_SPAN: Long = 200
        }

        init {
            delta = DEFAULT_QUALIFICATION_SPAN
            deltaClick = 0
        }
    }

👍

@danielandrioli
Copy link

Thanks, @Duna !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment