Как провести различие между броском и прикосновением?
У меня есть ListView внутри ViewFlipper, который я переворачиваю, когда пользователь проводит по экрану. Нажатие на 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;
}
2 ответа
Как обычно это делается, через родительское представление onInterceptTouchEvent
метод. onInterceptTouchEvent
имеет шанс увидеть любое событие касания, прежде чем его увидят дети. Если onInterceptTouchEvent
возвращается true
дочерний вид, который ранее обрабатывал сенсорные события, получает ACTION_CANCEL
и события с этого момента отправляются родителю onTouchEvent
метод для обычной обработки. Он также может вернуться false
и просто следите за событиями, пока они движутся вниз по иерархии представлений к своим обычным целям.
Вы хотите сделать это по существу в onInterceptTouchEvent
на родительском представлении, где вы обнаруживаете броски:
- На
ACTION_DOWN
, запишите местоположение касания. Вернутьfalse
, - На
ACTION_MOVE
, проверьте дельту между начальной позицией касания и текущей позицией. Если оно превышает пороговое значение, (каркас используетViewConfiguration#getScaledTouchSlop()
или другие соответствующие значения изViewConfiguration
за такие вещи, как) вернутьсяtrue
, - Обнаружить и обработать бросок как обычно на основе
onTouchEvent
,
Как только вы перехватите, ListView
отменит обработку касаний, и вы не получите нежелательные события касания в элементах списка. ListView
также настроен так, чтобы запретить его родителю перехватывать события, когда пользователь начал вертикальную прокрутку списка, что означает, что вы не получите ошибочные горизонтальные колебания, если пользователь небрежно бросает список по вертикали.
Вот как такие вещи, как стандартный Android Launcher или News and Weather, выполняют параллельное разбиение по страницам прокручиваемого / вставляемого контента.
Вы пытались использовать SimpleOnGestureListener.onSingleTapConfirmed(MotionEvent) для события касания ("щелчок")? Это будет вызвано только после того, как детектор будет уверен, что первое касание пользователя - это действительно касание, а не двойное касание (или, возможно, бросок).
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// Code...
}
}