OnInterceptTouchEvent, onTouchEvent только видеть ACTION_DOWN
У меня есть ViewGroup верхнего уровня, который я называю SliderView, в котором я хочу обнаружить прокрутку. Это в основном работает, но один странный отказ сохраняется.
Суть SliderView заключается в том, чтобы переопределить onInterceptTouchEvent и, как только пользователь на самом деле будет прокручивать, верните "true", чтобы другие представления не могли отображать MotionEvent. Вот фрагмент кода:
public class SliderView extends ViewGroup
{
enum MoveState { MS_NONE, MS_HSCROLL, MS_VSCROLL };
private MoveState moveState = MoveState.MS_NONE;
... other code ...
public boolean onInterceptTouchEvent(MotionEvent e)
{
final int action = e.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
moveState = MoveState.MS_NONE;
break;
case MotionEvent.ACTION_MOVE:
if (moveState == MoveState.MS_NONE)
{
if (motion is horizontal)
{
moveState = MoveState.MS_VSCROLL;
return true;
}
else
moveState = MoveState.MS_VSCROLL; // let child window handl MotionEvent
}
else if (moveState == MoveState.MS_HSCROLL)
return true; // don't let children see motion event.
}
return super.onInterceptTouchEvent (e);
}
... other code ...
}
Насколько я понимаю, мой SliderView (который является самым внешним видом) всегда должен получать onInterceptTouchEvent. В одном из моих тестов, где дочерний уровень верхнего уровня есть, однако в следующем случае это не так.
Когда дочерний элемент верхнего уровня является ScrollView, onInterceptTouchEvent получает ACTION_MOVE, а мой код делает то, что я хочу. В другом случае, когда дочерний элемент верхнего уровня является LinearLayout, иногда он прерывается: он всегда получает ACTION_DOWN, но получает ACTION_MOVE только в том случае, если пользователь касается виджета внутри LinearLayout; при касании пустой области происходит только ACTION_DOWN.
Я буду замечать, что он ведет себя так, как будто проблемы с отказом происходят вне SliderView. Однако, если это так, зачем мне получать события ACTION_DOWN?
Второе примечание: глядя на исходный код ScrollView, я вижу, что он проверяет "inChild"; Я не понял, для чего это и как это может быть важно.
Ответы
Ответ 1
Из-за ответа user123321 здесь
onInterceptTouchEvent только вызывается, если у родителя есть дочернее представление, которое возвращает "true" из onTouchEvent. Когда дочерний объект возвращает true, родитель теперь имеет возможность перехватить это событие
Ответ 2
Из ссылки разработчика Android (http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)):
"2.
.... Также, вернув true из onTouchEvent(), вы не получите никаких следующих событий в onInterceptTouchEvent(), и вся обработка касания должна произойти в onTouchEvent(), как обычно. "
Может быть, потому что ваш onTouchEvent всегда возвращает true..?
Ответ 3
Вам нужно только позвонить
requestDisallowInterceptTouchEvent(true);
на родительском представлении, например:
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
view.getParent().requestDisallowInterceptTouchEvent(true);
switch(motionEvent.getActio){
}
return false;
}
Ответ 4
При перехвате onTouchEvent есть две возможности для правильного перехвата касаний (все остальные по умолчанию).
-
Возвращает false в onInterceptTouchEvent()
@Override
public boolean onInterceptTouchEvent(MotionEvent me) {
return false;
}
-
Возвращает true в onTouchEvent()
@Override
public boolean onTouchEvent(MotionEvent me) {
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
log("MotionEvent.ACTION_DONE");
break;
case MotionEvent.ACTION_MOVE:
log("MotionEvent.ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
log("MotionEvent.ACTION_CANCEL");
userActionDown = false;
break;
case MotionEvent.ACTION_UP:
log("MotionEvent.ACTION_UP");
break;
}
return true;
}
-
Затем для вашего случая (и других). Выполняйте все ваши вычисления в onTouchEvent(), как показано выше. OnInterceptTouchEvent() будет вызываться только один раз для ACTION_DOWN. Но, onTouchEvent также получит событие ACTION_DOWN, и вам нужно вернуть true, а не супер.
Подробнее о onInterceptTouchEvent(): http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
ps - Когда вы задаете вопросы здесь, вы также должны написать описание того, что вы пытаетесь сделать. Возможно, вы, возможно, найдете гораздо лучшие способы сделать что-то. Для вашего случая навигации реальный ответ, который вы ищете, ViewPager. Он отлично работает и очень прост в реализации. Вы также должны ознакомиться с некоторыми другими удобными навигационными патчами, которые Android может предложить разработчикам: ссылка.