Как провести различие между броском и прикосновением?

У меня есть 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...
    }
}
Другие вопросы по тегам