MotionEvent.ACTION_UP未被调用
请考虑休耕(为了更好地理解我的问题)。
正如你所看到的,我正在考虑一个由填充包围的列表视图。 现在,如果用户按下列表视图项目,作为我已经提供了浅蓝色背景颜色的行动。 现在,我的应用程序正在处理onTouch事件本身来确定类似的操作
- 点击
- 从左到右滑动
- 从右到左滑动
这是我的代码。
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; }
正如你所看到的,我确定了MotionEvent.ACTION_UP中执行的动作,并相应地设置了Enum Action的值。 如果用户不跨越列表视图边界,这个逻辑就像一个魅力。
现在,如果用户在滑动(或具体地)沿着列表项移动他的手指从蓝色移动到橙色时,MotionEvent.ACTION_UP将不会被提供给列表视图,这导致我的代码不作出决定,并且由于翻译X ()方法和setAlpha(),因为在这种情况下没有确定Action,那个特定的列表项变为空白。
这个问题在这里并没有停止,因为我每次都没有查看充气的视图,同一个translationX()行每次膨胀导致多次出现空白/白色列表项。
有没有什么可以做,即使我没有遇到MotionEvent.ACTION_UP,我仍然可以做出决定?
谢谢。
你应该return true;
case MotionEvent.ACTION_DOWN:
,那么MotionEvent.ACTION_UP
将被处理。
正如View.OnTouchListener所解释的:
返回 :
如果侦听器消耗了该事件,则返回true,否则返回false。
ACTION_UP
在发生ACTION_UP
之前不会被调用,对此的逻辑解释是,如果在其之前从未发生ACTION_DOWN
,则不可能发生ACTION_UP
。
这个逻辑使得开发者能够在ACTION_DOWN
之后阻塞进一步的事件。
另外请注意,在某些情况下(例如,屏幕旋转),手势可能被取消,在这种情况下, MotionEvent.ACTION_UP
将不会被发送。 而是发送一个MotionEvent.ACTION_CANCEL
。 因此,一个正常的操作switch语句应该是这样的:
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 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 }
我不认为增加return true;
以案件MotionEvent.ACTION_DOWN:
将最终解决问题。 这只会让return false
的工作像魅力那样复杂化。
需要注意的是: MotionEvent.ACTION_DOWN: /*something*/ return true;
会阻止任何其他Listenercallback可用的视图,即使onClickListenerm,而在MotionEvent.ACTION_UP:
正确return false
MotionEvent.ACTION_UP:
可以帮助MotionEvent传播到正确的目的地。
参考他原来的代码sourse: https : //github.com/romannurik/android-swipetodismiss
正如Danpe在简洁的答案中解释的那样 – 我必须添加ACTION_DOWN代码才能识别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;
我有整个onTouch(..)方法返回true,所以我不知道为什么这是不够的,但很高兴有这个快速的解决scheme..(谢谢!)