MotionEvent.ACTION_UP not called

Consider the following diagram below (for a better understanding of my problem). enter image description here

As you can see, I am looking at a list view surrounded by indents. Now, if the user clicks on the list item, as the action I provided, this is a light blue background color. My app is now dealing with onTouch events to identify actions like

  • Click
  • Swipe left to right
  • Right to left Swipe

Here is my code

public boolean onTouch(View v, MotionEvent event) { if(v == null) { mSwipeDetected = Action.None; return false; } switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: { downX = event.getRawX(); downY = event.getRawY(); mSwipeDetected = Action.Start; // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); int childCount = listView.getChildCount(); int[] listViewCoords = new int[2]; listView.getLocationOnScreen(listViewCoords); int x = (int) event.getRawX() - listViewCoords[0]; int y = (int) event.getRawY() - listViewCoords[1]; View child; for (int i = 0; i < childCount; i++) { child = listView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } return false; // allow other events like Click to be processed } case MotionEvent.ACTION_MOVE: { upX = event.getRawX(); upY = event.getRawY(); float deltaX=0,deltaY=0; deltaX = downX - upX; deltaY = downY - upY; if(deltaY < VERTICAL_MIN_DISTANCE) { setTranslationX(mDownView, -(deltaX)); setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / listView.getWidth()))); return false; } else { forceBringBack(v); } return false; } case MotionEvent.ACTION_UP: { stopX = event.getX(); float stopValueY = event.getRawY() - downY; float stopValue = stopX - downX; if(!mDownView.isPressed()) { forceBringBack(mDownView); return false; } boolean dismiss = false; boolean dismissRight = false; if(Math.abs(stopValue)<10) { mSwipeDetected = Action.Start; } else { mSwipeDetected = Action.None; } String log = ""; Log.d(log, "Here is Y" + Math.abs(stopValueY)); Log.d(log, "First Comparison of Stop Value > with/4" + (Math.abs(stopValue) > (listView.getWidth() /4))); Log.d(log, "Second Comparison " + (Math.abs(stopValueY)<VERTICAL_MIN_DISTANCE)); Log.d(log, "Action Detected is " + mSwipeDetected + " with Stop Value " + stopValue); if((Math.abs(stopValue) > (listView.getWidth() /4))&&(Math.abs(stopValueY)<VERTICAL_MIN_DISTANCE)) { dismiss = true; dismissRight = stopValue > 0; if(stopValue>0) { mSwipeDetected = Action.LR; } else mSwipeDetected = Action.RL; } Log.d(log, "Action Detected is " + mSwipeDetected + " with Stop Value after dissmiss" + stopValue); if(dismiss) { if(dismissRight) mSwipeDetected = Action.LR; else mSwipeDetected = Action.RL; animate(mDownView) .translationX(dismissRight ? listView.getWidth() : - listView.getWidth()) .alpha(0) .setDuration(mAnimationTime) .setListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { } }); } else { animate(mDownView) .translationX(0) .alpha(1) .setDuration(mAnimationTime) .setListener(null); } break; } } return false; } 

As you can see, I define the completed action in MotionEvent.ACTION_UP and set the Enum Action value accordingly. This logic works like a talisman if the user does not cross the border of the list view.

Now, if the user, moving (or, in particular), moving his finger on the list item, moves from blue to orange, MotionEvent.ACTION_UP will not be passed to listview, which causes my code to not make a decision due to translationX () and setAlpha ( ), since in this case the action is not defined, this particular list item becomes empty.

The problem does not stop here, because, I do not inflate the view every time, the same line of translationX () inflates every time, leading to multiple occurrence of an empty / white list item.

Is there anything I can do so that even if I did not encounter MotionEvent.ACTION_UP, I could still make some kind of decision?

Thank you

+55
android android-listview listview
Apr 03 '13 at 23:10
source share
4 answers

You must return true; in case MotionEvent.ACTION_DOWN: therefore MotionEvent.ACTION_UP processed.




As explained on View.OnTouchListener :

Returns

True if the listener consumes the event; false otherwise.

MotionEvent.ACTION_UP It will not be called until MotionEvent.ACTION_DOWN , the logical explanation for this is the inability to ACTION_UP if ACTION_DOWN never occurred before it.

This logic allows the developer to block further events after ACTION_DOWN .

+174
May 11 '13 at 8:43
source share

Also note that under certain circumstances (for example, screen rotation) the gesture may be canceled, in which case MotionEvent.ACTION_UP will NOT be sent. Instead, MotionEvent.ACTION_CANCEL . Therefore, the normal action switch statement should look something like this:

 switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: // check if we want to handle touch events, return true // else don't handle further touch events, return false break; // ... handle other cases case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // finish handling touch events // note that these methods won't be called if 'false' was returned // from any previous events related to the gesture break; } 
+18
Apr 18 '16 at 5:09
source share

I do not think that adding return true; MotionEvent.ACTION_DOWN: in case MotionEvent.ACTION_DOWN: will ultimately solve the problem. This simply complicated the situation where return false could do the job like a charm.

What to look for: MotionEvent.ACTION_DOWN:/*something*/return true; will block any other Listener callbacks available for presentation, even onClickListenerm, while correctly MotionEvent.ACTION_UP: return false in MotionEvent.ACTION_UP: can help propagate the MotionEvent to the correct destination.

Link to its source code: https://github.com/romannurik/android-swipetodismiss

+6
Jun 19 '14 at 1:48
source share

As Dunpe explained in his short answer , I had to add the ACTION_DOWN code to recognize ACTION_UP.

  case MotionEvent.ACTION_DOWN: return true; case MotionEvent.ACTION_UP: XyPos xyPos = new XyPos(); xyPos.x = last_x; xyPos.y = last_y; handleViewElementPositionUpdate(xyPos); break; 

I had the whole onTouch (..) method returning true anyway, so I'm not sure why this was not enough ... but it's nice to have this quick solution .. (thanks!)

0
Nov 14 '13 at 20:53
source share



All Articles