如何区分投掷和触摸?
我在ViewFlipper中有一个ListView,当用户在屏幕上滑动时我正在翻转它。 单击ListView将打开浏览器。 有时当我轻扫时,它会在ListView上被检测为触摸并打开浏览器。 这可能很烦人。 我怎样才能防止这种情况发生?
class MyGestureDetector extends SimpleOnGestureListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { try { if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) return false; // right to left swipe if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { viewFlipper.setInAnimation(slideLeftIn); viewFlipper.setOutAnimation(slideLeftOut); viewFlipper.showNext(); } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { viewFlipper.setInAnimation(slideRightIn); viewFlipper.setOutAnimation(slideRightOut); viewFlipper.showPrevious(); } if (viewFlipper.getDisplayedChild() == 0) { // TODO: light up left flipperPosition = 0; } else if (viewFlipper.getDisplayedChild() == 1) { // TODO: light up middle flipperPosition = 1; } else if (viewFlipper.getDisplayedChild() == 2) { // TODO: light up right flipperPosition = 2; } } catch (Exception e) { System.out.println(e); } return false; } } protected MotionEvent downStart = null; public boolean onInterceptTouchEvent(MotionEvent event) { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: // keep track of the starting down-event downStart = MotionEvent.obtain(event); break; case MotionEvent.ACTION_MOVE: // if moved horizontally more than slop*2, capture the event for ourselves float deltaX = event.getX() - downStart.getX(); if(Math.abs(deltaX) > ViewConfiguration.getTouchSlop() * 2) return true; break; } // otherwise let the event slip through to children return false; }
通常这样做的方法是通过父视图的onInterceptTouchEvent
方法。 onInterceptTouchEvent
有机会在视图的子项之前看到任何触摸事件。 如果onInterceptTouchEvent
返回true
,则先前处理触摸事件的子视图将收到ACTION_CANCEL
并且从该点开始的事件将被发送到父级的onTouchEvent
方法以进行常规处理。 当它们沿着视图层次结构向下移动到通常的目标时,它也可以返回false
并简单地监视事件。
您想要在父视图上的onInterceptTouchEvent
中onInterceptTouchEvent
执行此onInterceptTouchEvent
,您将检测到flings:
- 在
ACTION_DOWN
,记录触摸的位置。 返回false
。 - 在
ACTION_MOVE
,检查初始ACTION_MOVE
位置和当前位置之间的差值。 如果超过阈值,(框架使用ViewConfiguration#getScaledTouchSlop()
或ViewConfiguration
其他适当值来执行此类操作,则返回true
。 - 基于
onTouchEvent
检测并处理onTouchEvent
。
拦截后, ListView
将取消其触摸处理,您不会在列表项上获得不需要的点击事件。 ListView
也设置为一旦用户开始垂直滚动列表就禁止其父级拦截事件,这意味着如果用户在垂直方向上拖动列表,则不会出现错误的水平偏移。
这就是Android启动器或新闻和天气这样的东西如何对滚动/可点击内容进行左右分页。
您是否尝试过使用SimpleOnGestureListener.onSingleTapConfirmed(MotionEvent)进行触摸事件(“点击”)? 只有在探测器确信用户的第一次点击确实是点击而不是双击(或希望是一次)时,才会调用此方法。
class MyGestureDetector extends SimpleOnGestureListener { @Override public boolean onSingleTapConfirmed(MotionEvent event) { // Code... } }