2011-09-16 2 views
17

Я не спрашиваю, как обрабатывать события касания, но что происходит за кулисами? Если есть несколько вложенных виджетов, в каком порядке они видят события? Имеет ли разработчик контроль над этим? В идеале я хотел бы получить документ по этому вопросу.Как поступают события Android touch?

ответ

21

С точки зрения активности:

сенсорных события доставляются первым Activity.dispatchTouchEvent. Здесь вы можете поймать их в первую очередь.

Здесь они отправляются в Окно, где они пересекают иерархию просмотра, в том порядке, в котором виджеты, которые нарисованы последними (поверх других виджетов), имеют возможность обрабатывать касание сначала в View.onTouchEvent. Если какой-либо вид возвращает true в onTouchEvent, то обход останавливается, а другие представления не получают события касания.

И, наконец, если View не затрагивает Touch, он доставлен в Activity.onTouchEvent.

Это все ваше управление. И логично, что то, что вы видите нарисованным поверх чего-то другого, имеет шанс обработать событие касания перед чем-то, что находится под ним.

+0

Есть ли у вас какой-либо документ, описывающий это? – DJClayworth

+0

О диспетчеризации: я могу читать исходный код и комментарии к функциям. О порядке просмотра - я прочитал его в каком-то документе, конечно же, на сайте developer.android.com, но не могу точно сказать, что именно. –

+0

В любом случае, хороший старт: http://developer.android.com/guide/topics/ui/ui-events.html –

10

Давайте посмотрим на наглядный пример.

enter image description here

Когда происходит касание события, первый каждый получает уведомление о событии, начиная с деятельностью и пройдя весь путь к виду сверху. Затем каждому дается возможность справиться с этим событием, начиная с представления сверху и полностью возвращаясь к Activity. Таким образом, деятельность является первой, кто узнает об этом, и последнему дается возможность справиться с этим.

enter image description here

Если активность или некоторое ViewGroup хочет обрабатывать сенсорное событие сразу (и не дать никому вниз линию шанса на него), то он может просто вернуться true в onInterceptTouchEvent().

Если View (или ViewGroup) имеет OnTouchListener, то событие касания обрабатывается OnTouchListener.onTouch(). В противном случае он обрабатывается onTouchEvent(). Если onTouchEvent() возвращает true для любого события касания, тогда обработка останавливается. Никто другой по линии не получает шанс на это.

Более подробное объяснение

Вышеприведенная схема делает вещи немного более простым, чем они на самом деле. Например, между Activity и ViewGroup A (корневой компоновкой) есть также Window и DecorView. Я оставил их выше, потому что нам вообще не нужно взаимодействовать с ними. Однако я включу их ниже. Нижеприведенное описание следует за событием касания через исходный код. Вы можете щелкнуть ссылку, чтобы увидеть фактический исходный код.

  1. Сообщество dispatchTouchEvent() получает уведомление о тележках. Событие касания передается как MotionEvent, которое содержит координаты x, y, время, тип события и другую информацию.
  2. Событие касания отправляется в окно superDispatchTouchEvent(). Window - абстрактный класс. Фактическая реализация - PhoneWindow.
  3. Следующая в очереди, чтобы получить уведомление, является DecorView's superDispatchTouchEvent().DecorView - это то, что обрабатывает строку состояния, панель навигации, область содержимого и т. Д. It is actually just a FrameLayout subclass, который сам является подклассом ViewGroup.
  4. Следующий, чтобы получить уведомление (исправьте меня, если я ошибаюсь) - это представление содержимого вашей деятельности. Это то, что вы задали в качестве корневого макета вашей деятельности в xml при создании макета в редакторе макетов Android Studio. Итак, выбираете ли вы RelativeLayout, LinearLayout или ConstraintLayout, все они являются подклассами ViewGroup. И ViewGroup получает уведомление о событии касания в dispatchTouchEvent(). Это ViewGroup A на моих диаграммах выше.
  5. ViewGroup будет notify any children у него есть событие касания, включая любых детей ViewGroup. Это ViewGroup B на моих диаграммах выше.
  6. В любом месте по пути, ViewGroup может short-circuit процесс уведомления, возвращая true за onInterceptTouchEvent().
  7. Предполагая, что ViewGroup вырезать короткие уведомления, естественный конец строки для уведомлений - это когда вызывается вызов dispatchTouchEvent().
  8. Теперь пришло время начать обработку событий. If there is an OnTouchListener, тогда он получает первый шанс при обработке события касания с onTouch(). Otherwise, View's onTouchEvent() получает, чтобы справиться с этим.
  9. Теперь все рекурсивные строки ViewGroups получают возможность обрабатывать событие касания так же, как и View. Хотя, я не указал это на диаграмме выше, ViewGroup является подклассом View, поэтому все, что я описал о OnTouchListener.onTouch() и onTouchEvent(), также применимо к ViewGroups.
  10. Finally, если никто больше этого не хочет, активность также получает последний шанс обработать событие с помощью onTouchEvent().

FAQ

Когда я когда-либо нужно переопределить dispatchTouchEvent()?

Возможно, вам не понадобится, если только вам не понадобится дополнительная маршрутизация, которая не возникает по умолчанию. Чтобы отслеживать уведомления о событии, вы можете вместо этого заменить onInterceptTouchEvent().

Когда мне когда-нибудь понадобится переопределить onInterceptTouchEvent()?

Если вы просто хотите следить за входящими уведомлениями о прикосновении, вы можете сделать это здесь и вернуть false.

Однако основная цель переопределения этого метода заключается в том, чтобы позволить ViewGroup обрабатывать определенный тип события касания, позволяя ребенку обрабатывать другой тип. Например, ScrollView делает это для обработки прокрутки, позволяя своему ребенку обрабатывать что-то вроде нажатия кнопки. И наоборот, если дочернее представление не хочет, чтобы его родитель украл свое событие касания, он может позвонить requestDisallowTouchIntercept().

Каковы типы событий касания?

Основными из них являются

  • ACTION_DOWN - Это начало сенсорного события. Вы должны всегда возвращать true для события ACTION_DOWN в onTouchEvent, если вы хотите обработать событие касания. В противном случае вы не получите больше событий, доставленных вам.
  • ACTION_MOVE - Это событие постоянно срабатывает при перемещении пальца по экрану.
  • ACTION_UP - Это последнее событие касания.

Бегун - ACTION_CANCEL. Это вызывается, если ViewGroup до дерева решает перехватить событие touch.

Вы можете просмотреть другие виды движущихся объектов here. Поскольку Android является мультитач, события также срабатывают, когда другие пальцы («указатели») касаются экрана.

Дальнейшее изучение

Смежные вопросы