Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Long Touch on a surfaceView ( android )

I'm making a game on Android and I need to do certain actions when the users attempts a long press on the screen. Unfortunately I haven't found any methods that works directly with a custom SurfaceView, feel free to tell me if such a method exists :)

So I decided to try and implement a long touch detection from the onTouch event listener.

here is my code:

@Override
    public boolean onTouch(View v, MotionEvent event)
    {
        long touchDuration = 0;


            if ( event.getAction() == MotionEvent.ACTION_DOWN )
            {
                //Start timer
                touchTime = System.currentTimeMillis();


            }else if ( event.getAction() == MotionEvent.ACTION_UP )
            {
                //stop timer
                touchDuration = System.currentTimeMillis() - touchTime;

                if ( touchDuration < 800 )
                {
                    onShortTouch(event,touchDuration);
                }else
                {
                    onLongTouch(event,touchDuration);
                }
            }
        }

        return true;

This works, but I can detect if the press was a long press or not only when the user stops touching the phone. So it's not exactly what I want. I would prefer if a timer would start when the user first touches the screen then once 800 ms is elapsed the LongTouch() method is called. In other words, I don't want to have to check how long has elapsed when ACTION_UP since ACTION_DOWN. I believe I should use a thread for the said timer but I can't make it work. When using the following code, the debug message is displayed as soon as I touch the screen:

        @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        long touchDuration = 0;

            TouchThread touchThread = new TouchThread();

            if ( event.getAction() == MotionEvent.ACTION_DOWN )
            {
                //Start timer
                touchTime = System.currentTimeMillis();
                touchThread.setEvent(event);
                touchThread.run();  
            }

        return true;
    }


    private class TouchThread extends Thread
    {

            public MotionEvent event = null;

            public void setEvent(MotionEvent e)
            {
                event = e;
            }

            @Override
            public void run()
            {
                long startTime = System.currentTimeMillis();
                long time = 0;

                while(event.getAction() == MotionEvent.ACTION_DOWN)
                {
                    time = System.currentTimeMillis() - startTime;
                    if( time > 800 )
                    {
                        System.out.println("LOOONG CLICK!!");
                        return;
                    }
                }
            }
    }

Has anyone got any idea ? An other solution would also be welcome.

Thanks.

like image 502
NioX5199 Avatar asked Jul 13 '10 10:07

NioX5199


3 Answers

It's quite easy, actually. In your view's constructor, do this:

setOnLongClickListener(new View.OnLongClickListener() 
{
   public boolean onLongClick(View v) {
        Log.v( "debug", "LONG CLICK!" );
        return true;
     }
  }
);

Then override onTouchEvent:

  @Override
  public boolean onTouchEvent(MotionEvent event) {
      super.onTouchEvent(event);
  }

And you're set ;).

like image 145
Overmacht Avatar answered Nov 16 '22 06:11

Overmacht


A nice option when you also want to do some manual event processing is the GestureDetector class: http://developer.android.com/reference/android/view/GestureDetector.html

How I use it is to make a GestureDetector instance in the constructor, implement the methods I'm interested in, and then at the start of the onTouchEvent() method do something like:

    if (gestureDetector.onTouchEvent(event)) {
        return true;
    }

Which then means in most cases when a gesture is detected that aborts the rest of your touch handling. However, long press is a little different because the long press method doesn't return a value. In this case I just have a boolean somewhere that I set when long press is triggered that I check later in the touch event handling method if necessary.

like image 33
Matt Hall Avatar answered Nov 16 '22 04:11

Matt Hall


One thing you can do is set the OnLongClickListener on your SurfaceView.

mySurfaceView.setOnLongClickListener(l);

Then in your SurfaceView, you need to override the onTouchEvent :

public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);
    return true;
}
like image 2
XGouchet Avatar answered Nov 16 '22 04:11

XGouchet