События касания, просачивающиеся вверх по иерархии, несмотря на «return true»

#android #event-handling #touch

#Android #обработка событий #коснитесь

Вопрос:

У меня есть проект, использующий ViewPager, который работает правильно: я могу переходить от просмотра к просмотру, щелкая влево и вправо.

На одной странице ViewPager у меня есть пользовательский вид, и я пытаюсь добавить под ним другое представление (LinearLayout), которое чувствительно к касанию и которое не будет «отображать» ViewPager. Вот так:

 <LinearLayout >

    <myView />

    <LinearLayout> // The touch sensitive region
    </LinearLayout>

</LinearLayout>
  

После того, как мой view был увеличен и добавлен в ViewPager, я вызываю setOnTouchListener(), чтобы присоединить слушателя к внутреннему LinearLayout. Слушатель возвращает «true».

К сожалению, когда я перемещаюсь по горизонтали в этом представлении, я перехожу на другую страницу. Я получаю следующие события: ACTION_DOWN, ACTION_MOVE (n раз) и, наконец, ACTION_CANCEL. Хотя я оставался в пределах представления.

Похоже, что событие поднялось по иерархии представлений и обработано ViewPager.

Есть ли логическое объяснение такому поведению?

Ответ №1:

Я нашел обходной путь, перехватывая события на уровне активности, переопределяя dispatchTouchEvent() .

Там я вызываю super.dispatchTouchEvent() для обработки всех событий, если пользователь не касается моего сенсорного представления. Я проверяю, находится ли пользователь на правильной странице и в нужном месте. В этом случае я сам обрабатываю событие.

 @Override
public boolean dispatchTouchEvent (MotionEvent ev) {


    if ( pager.getCurrentPosition()!=0 ) { // Test ViewPager page
            super.dispatchTouchEvent(ev);
    }   
    else {

        int[] xy = new int[2];
        findViewById(R.id.myTouchControl).getLocationOnScreen(xy);
        int topOfView = xy[1];

        if ( ev.getY() > topOfView ) {
            // Custom processing
            ...

        } else {
            // Standard processing
            super.dispatchTouchEvent(ev);
        }
    }
    return false;
}
  

Ответ №2:

Нет необходимости переопределять dispatchTouchEvent(). Вместо этого в событии ACTION_DOWN используйте View.getParent().requestDisallowInterceptTouchEvent(true) .

requestDisallowInterceptTouchEvent(true) запрашивает родительский просмотр (ViewPager) не перехватывать это конкретное событие касания. Этот флаг будет снят после завершения MotionEvent, поэтому вы должны вызвать его в ACTION_DOWN.