Take the 2-minute tour ×

I'm currently fiddling around with Android programming, but I have a small problem detecting different touch events, namely a normal touch press (press on the screen and release right away), a long press (touch the screen and hold the finger on it) and movement (dragging on the screen).

What I wanted to do is have an image (of a circle) on my screen which I can drag around. Then when I press it once (short/normal press) a Toast comes up with some basic information about it. When I long press it, an AlertDialog with a list comes up to select a different image (circle, rectangle or triangle).

I made a custom View with my own OnTouchListener to detect the events and draw the image in onDraw. The OnTouchListener.onTouch goes something like this:

// has a touch press started?
private boolean touchStarted = false;
// co-ordinates of image
private int x, y;

public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        touchStarted = true;
    else if (action == MotionEvent.ACTION_MOVE) {
        // movement: cancel the touch press
        touchStarted = false;

        x = event.getX();
        y = event.getY();

        invalidate(); // request draw
    else if (action == MotionEvent.ACTION_UP) {
        if (touchStarted) {
            // touch press complete, show toast
            Toast.makeText(v.getContext(), "Coords: " + x + ", " + y, 1000).show();

    return true;

The problem is that the press doesn't quite work as expected, because when I casually touch the screen it also detects a tiny bit of movement and cancels the touch press and moves around the image instead.

I "hacked" around this a bit my introducing a new variable "mTouchDelay" which I set to 0 on ACTION_DOWN, increase in MOVE and if it's >= 3 in MOVE I execute my "move" code. But I have a feeling this isn't really the way to go.

I also haven't found out how to detect a long press. The culprit really is the MOVE which seems to always trigger.

For an example of what I roughly want, see the Android application "DailyStrip": it shows an image of a comic strip. You can drag it if it's too large for the screen. You can tap it once for some controls to pop-up and long press it for an options menu.

PS. I'm trying to get it to work on Android 1.5, since my phone only runs on 1.5.

share|improve this question
This needs a Java tag. However, if you ever figure this out in a web app, accessible through jQuery, I'm trying to figure out how to intercept long tap (tap hold, long press) as well. –  Volomike Jan 17 '11 at 5:25
add comment

7 Answers

This code can distinguish between click and movement (drag, scroll). In onTouchEvent set a flag isOnClick, and initial X, Y coordinates on ACTION_DOWN. Clear the flag on ACTION_MOVE (minding that unintentional movement is often detected which can be solved with a THRESHOLD const).

private float mDownX;
private float mDownY;
private final float SCROLL_THRESHOLD = 10;
private boolean isOnClick;

public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mDownX = ev.getX();
            mDownY = ev.getY();
            isOnClick = true;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (isOnClick) {
                Log.i(LOG_TAG, "onClick ");
                //TODO onClick code
        case MotionEvent.ACTION_MOVE:
            if (isOnClick && (Math.abs(mDownX - ev.getX()) > SCROLL_THRESHOLD || Math.abs(mDownY - ev.getY()) > SCROLL_THRESHOLD)) {
                Log.i(LOG_TAG, "movement detected");
                isOnClick = false;
    return true;

For LongPress as suggested above, GestureDetector is the way to go. Check this Q&A:

Detecting a long press with Android

share|improve this answer
Thanks for clear code –  Mohsen Afshin May 13 '13 at 6:50
Anytime! :) Thanks for acknowledging. ;) –  MSquare May 14 '13 at 14:42
add comment

From the Android Docs -





As for the "moving happens even when I touch" I would set a delta and make sure the View has been moved by at least the delta before kicking in the movement code. If it hasn't been, kick off the touch code.

share|improve this answer
With onLongClick the long click "kind of" works, but I still face two problems. First off, onLongClick triggers twice for one long click (I simply show a Toast and return true, and I get 2 Toasts). Also, when I press and hold I get the long click while holding, but when I release I still get the ACTION_UP from the onTouch. How can I prevent the ACTION_UP from onTouch after onLongClick has triggered? –  pbean Dec 2 '10 at 13:15
The double onLongClick worries me, I'm not sure why it would be firing twice. As for the ACTION_UP still firing, I would ask why do you need to track ACTION_UP and ACTION_DOWN. Test to see if onTouch() gets fired when onLongClick() is fired. If not I'm not sure you need to capture those. You should only need onTouch() for when the item is actually touched and when it's moved. You can also look at using onClick() for "onTouch()" and using onTouch() for movement only. Not sure if that would meet your requirements, though. –  Jason L. Dec 2 '10 at 15:52
add comment

I discovered this after experimenting lots.

In the initialisation of your activity:

setOnLongClickListener(new View.OnLongClickListener() {
  public boolean onLongClick(View view) {
    return true;  // avoid extra click events
setOnTouch(new View.OnTouchListener(){
  public boolean onTouch(View v, MotionEvent e){
    switch(e.getAction & MotionEvent.ACTION_MASK){
      // do drag/gesture processing. 
    // you MUST return false for ACTION_DOWN and ACTION_UP, for long click to work
    // you can return true for ACTION_MOVEs that you consume. 
    // DOWN/UP are needed by the long click timer.
    // if you want, you can consume the UP if you have made a drag - so that after 
    // a long drag, no long-click is generated.
    return false;
share|improve this answer
what do you mean with 'consume the UP'? Sorry, newbie here. –  Luis A. Florit Nov 4 '12 at 16:27
Oh - If I am sent an event, I can "consume" it, meaning that other hooks that are listening for the same event don't get called as well. For example, when I lift my hand from the screen, an "UP" message may be sent along the component hierarchy unless I consume it. –  Sanjay Manohar Nov 8 '12 at 21:05
I see. I understand what you wrote in principle, but how do you actually 'consume', say, the 'UP' event? –  Luis A. Florit Nov 8 '12 at 23:06
Ah - consuming an event is done simply by returning true from the onTouch or onLongClick function. The window's thread which calls this handler method checks, after dispatching the event to your function, whether you return T/F. –  Sanjay Manohar Jun 19 '13 at 22:53
Got it now. Thanks! –  Luis A. Florit Jun 20 '13 at 3:33
add comment

I was looking for a similar solution and this is what I would suggest. In the OnTouch method, record the time for MotionEvent.ACTION_DOWN event and then for MotionEvent.ACTION_UP, record the time again. This way you can set your own threshold also. After experimenting few times you will know the max time in millis it would need to record a simple touch and you can use this in move or other method as you like.

Hope this helped. Please comment if you used a different method and solved your problem.

share|improve this answer
add comment

I think you should implement GestureDetector.OnGestureListener as described in Using GestureDetector to detect Long Touch, Double Tap, Scroll or other touch events in Android and androidsnippets and then implement tap logic in onSingleTapUp and move logic in onScroll events

share|improve this answer
add comment

I was just dealing with this mess after wanting longclick to not end with a click event.

Here's what I did.

public boolean onLongClick(View arg0) {
    Toast.makeText(getContext(), "long click", Toast.LENGTH_SHORT).show();
    longClicked = true;
    return false;

public void onClick(View arg0) {
        Toast.makeText(getContext(), "click", Toast.LENGTH_SHORT).show();
    longClick = false; // sets the clickability enabled

boolean longClicked = false;

It's a bit of a hack but it works.

share|improve this answer
add comment

it just needed a ontouch event in the overlay class. check this, it helped me


share|improve this answer
add comment

Your Answer


