Detect long print using Android

I am currently using

onTouchEvent(MotionEvent event){ } 

to detect when the user clicks my glSurfaceView, there is a way to detect when a long click is made. I assume that if I cannot find much in dev docs, then this will be some kind of work around the method. Something like registering ACTION_DOWN and seeing how long it takes until ACTION_UP.

How do you detect long clicks on android using opengl-es?

+67
java android touchscreen long-click
Oct 27 '11 at 17:25
source share
10 answers

Try the following:

 final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { public void onLongPress(MotionEvent e) { Log.e("", "Longpress detected"); } }); public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); }; 
+101
Oct 27 '11 at 19:42
source share
— -

GestureDetector is the best solution.

Here is an interesting alternative. OnTouchEvent uses Runnable for each ACTION_DOWN chart to run after 1 second. On each ACTION_UP or ACTION_MOVE, cancel the scheduled Runnable. If ACTION_DOWN is disabled for less than 1 second , Runnable will not work.

 final Handler handler = new Handler(); Runnable mLongPressed = new Runnable() { public void run() { Log.i("", "Long press!"); } }; @Override public boolean onTouchEvent(MotionEvent event, MapView mapView){ if(event.getAction() == MotionEvent.ACTION_DOWN) handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout()); if((event.getAction() == MotionEvent.ACTION_MOVE)||(event.getAction() == MotionEvent.ACTION_UP)) handler.removeCallbacks(mLongPressed); return super.onTouchEvent(event, mapView); } 
+148
Jul 27 2018-12-12T00:
source share

I have a code that detects a click, a long click and movement. This is a rather complicated combination of the answers above and the changes I have made to each page of the documentation.

 //Declare this flag globally boolean goneFlag = false; //Put this into the class final Handler handler = new Handler(); Runnable mLongPressed = new Runnable() { public void run() { goneFlag = true; //Code for long click } }; //onTouch code @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: handler.postDelayed(mLongPressed, 1000); //This is where my code for movement is initialized to get original location. break; case MotionEvent.ACTION_UP: handler.removeCallbacks(mLongPressed); if(Math.abs(event.getRawX() - initialTouchX) <= 2 && !goneFlag) { //Code for single click return false; } break; case MotionEvent.ACTION_MOVE: handler.removeCallbacks(mLongPressed); //Code for movement here. This may include using a window manager to update the view break; } return true; } 

I confirm that it works, since I used it in my application.

+5
Mar 22 '15 at 8:02
source share

When you mean clicking on a user, do you mean click? A click is when the user clicks down and then immediately lifts his finger. Therefore, it covers two onTouch events. You should keep using onTouchEvent for things that happen on initial touch or after release.

Therefore, you should use onClickListener if it is a click.

Your answer is similar: use onLongClickListener.

+3
Oct 27 '11 at 18:45
source share

I created a snippet - inspired by the actual view source - that reliably detects long clicks / clicks with custom delay. But this is in Kotlin:

 val LONG_PRESS_DELAY = 500 val handler = Handler() var boundaries: Rect? = null var onTap = Runnable { handler.postDelayed(onLongPress, LONG_PRESS_DELAY - ViewConfiguration.getTapTimeout().toLong()) } var onLongPress = Runnable { // Long Press } override fun onTouch(view: View, event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { boundaries = Rect(view.left, view.top, view.right, view.bottom) handler.postDelayed(onTap, ViewConfiguration.getTapTimeout().toLong()) } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { handler.removeCallbacks(onLongPress) handler.removeCallbacks(onTap) } MotionEvent.ACTION_MOVE -> { if (!boundaries!!.contains(view.left + event.x.toInt(), view.top + event.y.toInt())) { handler.removeCallbacks(onLongPress) handler.removeCallbacks(onTap) } } } return true } 
+2
Feb 05 '17 at 16:03
source share

The MSquare solution only works if you hold a specific pixel, but this is an unreasonable expectation for the end user if they don’t use a mouse (which they don’t use, they use their fingers).

So, I added a little threshold for the distance between DOWN and UP, in case there was a MOVE action between them.

 final Handler longPressHandler = new Handler(); Runnable longPressedRunnable = new Runnable() { public void run() { Log.e(TAG, "Long press detected in long press Handler!"); isLongPressHandlerActivated = true; } }; private boolean isLongPressHandlerActivated = false; private boolean isActionMoveEventStored = false; private float lastActionMoveEventBeforeUpX; private float lastActionMoveEventBeforeUpY; @Override public boolean dispatchTouchEvent(MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN) { longPressHandler.postDelayed(longPressedRunnable, 1000); } if(event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_HOVER_MOVE) { if(!isActionMoveEventStored) { isActionMoveEventStored = true; lastActionMoveEventBeforeUpX = event.getX(); lastActionMoveEventBeforeUpY = event.getY(); } else { float currentX = event.getX(); float currentY = event.getY(); float firstX = lastActionMoveEventBeforeUpX; float firstY = lastActionMoveEventBeforeUpY; double distance = Math.sqrt( (currentY - firstY) * (currentY - firstY) + ((currentX - firstX) * (currentX - firstX))); if(distance > 20) { longPressHandler.removeCallbacks(longPressedRunnable); } } } if(event.getAction() == MotionEvent.ACTION_UP) { isActionMoveEventStored = false; longPressHandler.removeCallbacks(longPressedRunnable); if(isLongPressHandlerActivated) { Log.d(TAG, "Long Press detected; halting propagation of motion event"); isLongPressHandlerActivated = false; return false; } } return super.dispatchTouchEvent(event); } 
+1
Aug 17 '15 at 14:28
source share

The idea is to create a Runnable to perform a long click in the future, but this execution may be canceled due to a click or movement.

You should also know when a long click was consumed, and when it is canceled because the fingers move too much. We use initialTouchX & initialTouchY to check if the user leaves the square area of ​​10 pixels, 5 on each side.

Here is my complete code for delegating Click & LongClick from Cell to ListView for Activity with OnTouchListener :

  ClickDelegate delegate; boolean goneFlag = false; float initialTouchX; float initialTouchY; final Handler handler = new Handler(); Runnable mLongPressed = new Runnable() { public void run() { Log.i("TOUCH_EVENT", "Long press!"); if (delegate != null) { goneFlag = delegate.onItemLongClick(index); } else { goneFlag = true; } } }; @OnTouch({R.id.layout}) public boolean onTouch (View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout()); initialTouchX = motionEvent.getRawX(); initialTouchY = motionEvent.getRawY(); return true; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_CANCEL: if (Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) { handler.removeCallbacks(mLongPressed); return true; } return false; case MotionEvent.ACTION_UP: handler.removeCallbacks(mLongPressed); if (goneFlag || Math.abs(motionEvent.getRawX() - initialTouchX) > 5 || Math.abs(motionEvent.getRawY() - initialTouchY) > 5) { goneFlag = false; return true; } break; } Log.i("TOUCH_EVENT", "Short press!"); if (delegate != null) { if (delegate.onItemClick(index)) { return false; } } return false; } 



ClickDelegate is an interface for sending click events to a handler class, e.g. Activity

  public interface ClickDelegate { boolean onItemClick(int position); boolean onItemLongClick(int position); } 

And all you need is to implement it in your Activity or parent View if you need to delegate behavior:

 public class MyActivity extends Activity implements ClickDelegate { //code... //in some place of you code like onCreate, //you need to set the delegate like this: SomeArrayAdapter.delegate = this; //or: SomeViewHolder.delegate = this; //or: SomeCustomView.delegate = this; @Override public boolean onItemClick(int position) { Object obj = list.get(position); if (obj) { return true; //if you handle click } else { return false; //if not, it could be another event } } @Override public boolean onItemLongClick(int position) { Object obj = list.get(position); if (obj) { return true; //if you handle long click } else { return false; //if not, it a click } } } 
+1
May 16 '18 at 15:58
source share
 setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { int action = MotionEventCompat.getActionMasked(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: longClick = false; x1 = event.getX(); break; case MotionEvent.ACTION_MOVE: if (event.getEventTime() - event.getDownTime() > 500 && Math.abs(event.getX() - x1) < MIN_DISTANCE) { longClick = true; } break; case MotionEvent.ACTION_UP: if (longClick) { Toast.makeText(activity, "Long preess", Toast.LENGTH_SHORT).show(); } } return true; } }); 
0
Mar 27 '16 at 4:32
source share

Here is an approach based on MSquare’s excellent idea for detecting a long press of a button, which has an additional function: the operation is not only executed in response to a long press, but the operation is repeated until the message MotionEvent.ACTION_UP appears. received. In this case, the actions of long and short pressing are the same, but they can be different.

Note that, as others have reported, deleting the callback in response to the MotionEvent.ACTION_MOVE message prevented the callback from being executed, since I could not hold my finger in my hands. I circumvented this issue by ignoring this message.

 private void setIncrementButton() { final Button btn = (Button) findViewById(R.id.btn); final Runnable repeater = new Runnable() { @Override public void run() { increment(); final int milliseconds = 100; btn.postDelayed(this, milliseconds); } }; btn.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { increment(); v.postDelayed(repeater, ViewConfiguration.getLongPressTimeout()); } else if (e.getAction() == MotionEvent.ACTION_UP) { v.removeCallbacks(repeater); } return true; } }); } private void increment() { Log.v("Long Press Example", "TODO: implement increment operation"); } 
0
Jan 29 '19 at 23:03
source share

I found one solution, and it does not require a definition of workable or other things, and it works fine.

  var lastTouchTime: Long = 0 // ( ViewConfiguration.#.DEFAULT_LONG_PRESS_TIMEOUT =500) val longPressTime = 500 var lastTouchX = 0f var lastTouchY = 0f view.setOnTouchListener { v, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { lastTouchTime = SystemClock.elapsedRealtime() lastTouchX = event.x lastTouchY = event.y return@setOnTouchListener true } MotionEvent.ACTION_UP -> { if (SystemClock.elapsedRealtime() - lastTouchTime > longPressTime && Math.abs(event.x - lastTouchX) < 3 && Math.abs(event.y - lastTouchY) < 3) { Log.d(TAG, "Long press") } return@setOnTouchListener true } else -> { return@setOnTouchListener false } } } 
0
Jul 17 '19 at 5:48
source share



All Articles