如何区分猛击和触摸?
我在 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;
}
I have a ListView inside of a ViewFlipper which I am flipping when the user swipes across the screen. Clicking on a ListView will open the browser. Sometimes when I am swiping, it gets detected as a touch on the ListView and will open the browser. This can be annoying. How can I prevent this from happening?
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
通常完成此操作的方式是通过父视图的
onInterceptTouchEvent
方法。onInterceptTouchEvent
有机会在视图的子视图之前看到任何触摸事件。如果onInterceptTouchEvent
返回true
,之前处理触摸事件的子视图会收到ACTION_CANCEL
,并且从该点开始的事件将被发送到父视图的< code>onTouchEvent 方法用于通常的处理。它还可以返回 false 并简单地监视事件,因为它们沿着视图层次结构到达其通常的目标。您实际上希望在检测滑动的父视图上的
onInterceptTouchEvent
中执行此操作:ACTION_DOWN
上,记录触摸的位置。返回假
。ACTION_MOVE
上,检查初始着陆位置和当前位置之间的增量。如果超过阈值,(框架使用ViewConfiguration #getScaledTouchSlop()
或来自ViewConfiguration
的其他适当值(对于此类情况)返回true
。onTouchEvent
照常检测并处理 fling。一旦拦截,
ListView
将取消其触摸处理,并且您不会在列表项上收到不需要的点击事件。ListView
还设置为一旦用户开始垂直滚动列表,就不允许其父级拦截事件,这意味着如果用户马虎地垂直滑动列表,您不会得到错误的水平滑动。这就是像 Android Launcher 或新闻和天气这样的东西如何对滚动/可点击内容进行左右分页。
The way this is normally done is through the parent view's
onInterceptTouchEvent
method.onInterceptTouchEvent
has a chance to see any touch event before a view's children do. IfonInterceptTouchEvent
returnstrue
the child view that was previously handling touch events receives anACTION_CANCEL
and the events from that point forward are sent to the parent'sonTouchEvent
method for the usual handling. It can also returnfalse
and simply spy on events as they travel down the view hierarchy to their usual targets.You want to do essentially this in
onInterceptTouchEvent
on the parent view where you're detecting the flings:ACTION_DOWN
, record the location of the touch. Returnfalse
.ACTION_MOVE
, check the delta between initial touch down position and current position. If it's past a threshold value, (the framework usesViewConfiguration#getScaledTouchSlop()
or other appropriate values fromViewConfiguration
for things like this,) returntrue
.onTouchEvent
.Once you intercept, the
ListView
will cancel its touch handling and you won't get unwanted tap events on your list items.ListView
is also set up to disallow its parent from intercepting events once the user has started vertically scrolling the list, which means you won't get mistaken horizontal flings if the user sloppily flings the list vertically.This is how things like the stock Android Launcher or News and Weather do side to side paging of scrolling/tappable content.
您是否尝试过使用 SimpleOnGestureListener.onSingleTapConfirmed(MotionEvent) 来处理触摸事件(“单击”)?仅当检测器确信用户的第一次点击确实是点击而不是双击(或者希望是猛击)后,才会调用此方法。
Have you tried using SimpleOnGestureListener.onSingleTapConfirmed(MotionEvent) for the on touch event ("click")? This will only be called after the detector is confident that the user's first tap is really a tap and not a double tap (or hopefully a fling).