2015-07-21 7 views
7

Как найти вид, вызывающий MotionEvent ACTION_CANCEL? У меня есть представление «А», которое получает ACTION_CANCEL, и я не хочу, чтобы это произошло. Где-то вид «B» «поглощает» MotionEvent. Я надеюсь, что есть способ узнать, кто такой «Б», поэтому я могу решить эту проблему.Как найти исходный вид MotionEvent ACTION_CANCEL

Я пробовал просмотреть мой код для различных обработчиков OnTouchEvent() и OnInterceptTouchEvent(), но еще не нашел виновника.

Я также поставил точку останова в проблемном ACTION_CANCEL, но не смог распознать что-либо в MotionEvent, который может представлять «B».

+0

Вы получаете начальное событие 'ACTION_DOWN'? – Barend

+0

Да, и серия ACTION_MOVE. –

+0

Я собирался спросить, можете ли вы просто заглянуть в представление под начальным событием, но я понял, что это не поможет, так что не возражайте, извините. – Barend

ответ

2

Если у вас есть вопрос правильно, вы получаете ACTION_CANCEL, вероятно, у родителя, и вам нужно найти этот вид. Учитывая события X и Y, вы можете найти представление, которое содержит эти координаты в первый момент, произошло ACTION_CANCEL. Попробуйте вызвать этот метод либо с верхним родителем (android.R.id.content), либо с ViewGroup, с которым вы имеете дело.

private View findViewAt(View contentView, int eventX, int eventY) { 
      ArrayList<View> unvisited = new ArrayList<View>(); 
      unvisited.add(contentView); 
      while (!unvisited.isEmpty()) { 
       View child = unvisited.remove(0); 
       if(isViewContains(child, eventX, eventY) { 
        Log.i(TAG, "view found! "); 
        unvisited.clear(); 
        return child; 
       } 
       if (!(child instanceof ViewGroup)){ 
        continue; 
       } 
       ViewGroup group = (ViewGroup) child; 
       final int childCount = group.getChildCount(); 
       for (int i=0; i< childCount; i++){ 
        unvisited.add(group.getChildAt(i)); 
       } 
      } 
     return null; 
    } 


private boolean isViewContains(View view, int eventX, int eventY) { 
    int[] location = new int[2]; 
    view.getLocationOnScreen(location); 
    int x = location[0]; 
    int y = location[1]; 
    int width = view.getWidth(); 
    int height = view.getHeight(); 
    return eventX < x || eventX > x + width || eventY < y || eventY > y + height; 
} 
+0

Это хорошая идея. Однако два комментария. (1) Разве eventX, eventY в представлении локальные координаты? Для работы isViewContains() нам нужны координаты экрана. (2) Я думаю, что алгоритм может быть сделан непосредственно с древовидной дорожкой - не нужно для очереди - или я что-то упускаю. –

+0

Это будет ходить по всем представлениям в иерархии. –

+0

Согласен, хотя точка 2 по-прежнему сохраняется. Несмотря на это, точка 1 является ключом. Если eventX, eventY находятся в локальных коордах, я не вижу способа сказать, из какого вида они пришли. –

1

На моем опыте, случай, который делает вид получить событие ACTION_CANCEL после А прикоснулись пользователями, и они тащат их палец из области А, если вы сталкиваетесь с этим делом, добавить метод для проверки расположение на dispatchTouchEvent() может помочь.

6

Если родитель перехватывает событие движения, единственный способ предотвратить это - предотвратить родительский элемент от , перехватывая это событие. Это можно хорошо управлять двумя способами.

Не видя конкретного кода и не требуя обобщенного решения, я предлагаю следующее.

Я хотел бы предложить управлять своими сенсорными мероприятиями для родителей и ребенком, управляя обработчиками событий
requestDisallowInterceptTouchEvent(boolean) и

onInterceptTouchEvent(android.view.MotionEvent) каждого вид/ViewGroup в затрагиваемом виде A, B C.

По не разрешая родительские перехваты в дочернем элементе, это помогает вам поймать родительские перехваты, которые вы не учли, а также настроить и изменить дочерние элементы из одного родителя.

Это должно управляться с вашего самого высокого родителя вашего вида/viewGroup и управляться через все родительские и дочерние отношения .

Проверка списка, любого элемента со встроенными событиями касания.

android.com/training/gestures/viewgroup

С точки зрения нахождения зрения нарушителя, который перехватывает событие, которое не может быть решен только логикой:

Пройтись каждого родителя к ребенку/родителя зрения ребенка. Методически проверьте обработку ontouch в каждой группе просмотра/просмотра , как показано на моей диаграмме.

View diagram

Существует еще некоторые детали в этих ответах здесь:
https://stackoverflow.com/a/30966413/3956566
https://stackoverflow.com/a/6384443/3956566

Я уверен, что вы это понимаете, но мне, это самое простое решение.

Помимо этого, нам нужно посмотреть на код, чтобы устранить его.

+0

Ну, похоже, что ответ на мой вопрос: «нет прямого метод». Другими словами, к тому времени, когда ACTION_CANCEL будет получен каким-либо произвольным представлением, источник ACTION_CANCEL будет потерян. Очень жаль. Я ценю вашу предложенную методологию, и это на самом деле более или менее то, что я делал, - в основном, глядя на цепочку родителей, чтобы увидеть, кто может отменить. Очень мало - это мой код (это макеты и виджеты Android), поэтому становится трудно пробираться через «чужой» исходный код, чтобы размышлять о происхождении ACTION_CANCEL. –

+0

Я действительно не чувствую, что вы ответили на вопрос, но вы пришли ближе, и вы приложили немало усилий. Ненавижу видеть, что щедрость тоже потрачена впустую. Итак, ура! –

+0

@PeriHartman Спасибо! знаю, что я не получил этого конкретного решения для вас, мне понравился и поддержал другой ответ.Вы дали мне пищу для размышлений, и если я придумаю способ петли через дерево представлений, я обновлю и дам вам знать. –