Лучшее место для демистификации это исходный код. Документы крайне неадекватны для объяснения этого.
dispatchTouchEvent фактически определено для Activity, View и ViewGroup. Думайте об этом как о контроллере, который решает, как маршрутизировать сенсорные события.
Например, самый простой случай - это случай View.dispatchTouchEvent, который направит событие касания либо в OnTouchListener.onTouch, если оно определено, либо в метод расширения onTouchEvent .
Для ViewGroup.dispatchTouchEvent все намного сложнее. Он должен выяснить, какое из его дочерних представлений должно получить событие (вызывая child.dispatchTouchEvent). Это в основном алгоритм тестирования попадания, в котором вы выясняете, какой ограничительный прямоугольник дочернего представления содержит координаты точки касания.
Но прежде чем он сможет отправить событие в соответствующее дочернее представление, родитель может шпионить и / или перехватить событие все вместе. Вот для чего предназначен onInterceptTouchEvent . Таким образом, он вызывает этот метод в первую очередь перед выполнением тестирования на попадание, и если событие было угнано (возвращая true из onInterceptTouchEvent), он отправляет ACTION_CANCEL дочерним представлениям, чтобы они могли отказаться от обработки события касания (от предыдущих событий касания) и с этого времени все сенсорные события на родительском уровне отправляются в onTouchListener.onTouch (если определено) или onTouchEvent (). Также в этом случае onInterceptTouchEvent никогда не вызывается снова.
Хотели бы вы переопределить [Activity | ViewGroup | View] .dispatchTouchEvent? Если вы не делаете какую-то пользовательскую маршрутизацию, вы, вероятно, не должны.
Основными методами расширения являются ViewGroup.onInterceptTouchEvent, если вы хотите шпионить и / или перехватывать событие касания на родительском уровне, и View.onTouchListener / View.onTouchEvent для обработки основного события.
В целом его слишком сложный дизайн, но Android Apis больше склоняется к гибкости, чем к простоте.
Потому что это первый результат в Google. Я хочу поделиться с вами отличным выступлением Дэйва Смита на Youtube: освоение сенсорной системы Android и слайды доступны здесь . Это дало мне хорошее глубокое понимание системы Android Touch:
Как Активность ручки потрогать:
Как сенсорный вид обрабатывает:
Как ViewGroup обрабатывает прикосновения:
Он также предоставляет пример кода пользовательского интерфейса на github.com/devunwired/ .
Ответ: в основном
dispatchTouchEvent()
вызывается на каждомView
слое, чтобы определитьView
, заинтересован ли а в продолжающемся жесте. В имеет способность красть сенсорные события в его -методе, прежде чем он будет звонить на детях. Команда только остановит диспетчеризацию, если -method вернет true. Разница в том , что в диспетчерских и говорит , если он должен перехватить (не диспетчеризация детей) или нет (диспетчерские ребенок) .ViewGroup
ViewGroup
dispatchTouchEvent()
dispatchTouchEvent()
ViewGroup
ViewGroup
onInterceptTouchEvent()
dispatchTouchEvent()
MotionEvents
onInterceptTouchEvent
MotionEvent
Вы могли бы представить, что код ViewGroup делает более или менее это (очень упрощенно):
источник
Дополнительный ответ
Вот некоторые визуальные дополнения к другим ответам. Мой полный ответ здесь .
dispatchTouchEvent()
МетодViewGroup
использованияonInterceptTouchEvent()
выбрать , следует ли немедленно обработать событие прикосновения (сonTouchEvent()
) или продолжать уведомляющие оdispatchTouchEvent()
методах своих детей.источник
В этих методах много путаницы, но на самом деле все не так сложно. Большая часть путаницы заключается в том, что:
View/ViewGroup
или любой из его детей не вернет trueonTouchEvent
,dispatchTouchEvent
иonInterceptTouchEvent
будет вызвано ТОЛЬКОMotionEvent.ACTION_DOWN
. Без истинного значенияonTouchEvent
родительское представление будет предполагать, что вашему представлению не нужны MotionEvents.MotionEvent.ACTION_DOWN
, даже если ваша ViewGroup возвращает true вonTouchEvent
.Порядок обработки таков:
dispatchTouchEvent
называется.onInterceptTouchEvent
вызываетсяMotionEvent.ACTION_DOWN
или когда любой из потомков ViewGroup вернул true вonTouchEvent
.onTouchEvent
сначала вызывается для дочерних элементов ViewGroup, а когда ни один из дочерних элементов не возвращает true, он вызывается дляView/ViewGroup
.Если вы хотите просмотреть
TouchEvents/MotionEvents
без отключения событий для ваших детей, вы должны сделать две вещи:dispatchTouchEvent
чтобы просмотреть событие и вернутьсяsuper.dispatchTouchEvent(ev)
;onTouchEvent
и верните true, иначе вы не получите ничего,MotionEvent
кромеMotionEvent.ACTION_DOWN
.Если вы хотите обнаружить какой-либо жест, например событие смахивания, не отключая другие события для ваших детей, если вы не обнаружили этот жест, вы можете сделать это следующим образом:
onInterceptTouchEvent
если ваш флаг установлен для отмены обработки MotionEvent вашими детьми. Это также удобное место для сброса вашего флага, потому что onInterceptTouchEvent больше не будет вызываться до следующегоMotionEvent.ACTION_DOWN
.Пример переопределения в
FrameLayout
(мой пример на C #, так как я программирую на Xamarin Android, но логика в Java такая же):источник
Я нашел очень интуитивное объяснение на этой странице http://doandroids.com/blogs/tag/codeexample/ . Взятые оттуда:
источник
dispatchTouchEvent обрабатывает перед onInterceptTouchEvent.
Используя этот простой пример:
Вы можете видеть, что журнал будет выглядеть так:
Таким образом, в случае, если вы работаете с этими двумя обработчиками, используйте dispatchTouchEvent для первой обработки события, которое перейдет к onInterceptTouchEvent.
Другое отличие состоит в том, что если dispatchTouchEvent возвращает «false», событие не распространяется на дочерний элемент, в данном случае это EditText, тогда как если вы возвращаете false в onInterceptTouchEvent, событие все равно получает диспетчеризацию для EditText.
источник
Краткий ответ:
dispatchTouchEvent()
будет вызван в первую очередь.Краткий совет: не следует переопределять,
dispatchTouchEvent()
так как это трудно контролировать, иногда это может замедлить вашу производительность. ИМХО, предлагаю переопределитьonInterceptTouchEvent()
.Поскольку в большинстве ответов довольно четко упоминается событие касания потока в группе действий / представлении / представлении, я добавляю более подробную информацию о коде этих методов в
ViewGroup
(игнорируяdispatchTouchEvent()
):onInterceptTouchEvent()
будет вызван первым, событие ACTION будет вызвано соответственно down -> move -> up. Есть 2 случая:Если вы вернете false в 3 случаях (ACTION_DOWN, ACTION_MOVE, ACTION_UP), он будет считать, что родитель не нуждается в этом событии касания , поэтому
onTouch()
родители никогда не звонят , аonTouch()
дети будут звонить вместо этого ; однако, пожалуйста, обратите внимание:onInterceptTouchEvent()
еще продолжают получать сенсорное событие, пока его дети не звонятrequestDisallowInterceptTouchEvent(true)
.onTouch()
родителям.И наоборот, если вы вернете true , родитель немедленно украдет это событие касания и
onInterceptTouchEvent()
немедленно остановится, вместоonTouch()
того, чтобы будут вызваны родители, а также всеonTouch()
дети получат последнее событие действия - ACTION_CANCEL (таким образом, это означает, что родители украл сенсорное событие, и дети не смогут с этим справиться). ПотокonInterceptTouchEvent()
return false является нормальным, но есть небольшая путаница с возвратом true case, поэтому я перечислю это здесь:onTouch()
из родителей получит ACTION_DOWN снова и последующие действия (ACTION_MOVE, ACTION_UP).onTouch()
родители получат следующий ACTION_MOVE (не тот же ACTION_MOVE вonInterceptTouchEvent()
) и следующие действия (ACTION_MOVE, ACTION_UP).onTouch()
родители НЕ будут звонить вообще, так как слишком поздно, чтобы родители украли событие касания.Еще одна важная вещь - ACTION_DOWN события в
onTouch()
будет определять, хочет ли представление получить больше действий от этого события или нет. Если представление возвращает значение true в ACTION_DOWNonTouch()
, это означает, что представление готово получить больше действий от этого события. В противном случае возврат false в ACTION_DOWN inonTouch()
будет означать, что представление не получит больше действий от этого события.источник
Вы можете найти ответ в этом видео https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19 и следующих 3 видео. Все события касания объяснены очень хорошо, это очень ясно и полно примеров.
источник
Следующий код внутри подкласса ViewGroup не позволит его родительским контейнерам получать события касания:
Я использовал это с пользовательским наложением, чтобы фоновые представления не реагировали на сенсорные события.
источник
Основное отличие:
источник
ViewGroup
onInterceptTouchEvent()
всегда является точкой входа дляACTION_DOWN
события, которое является первым событием, которое должно произойти.Если вы хотите, чтобы ViewGroup обработал этот жест, верните true из
onInterceptTouchEvent()
. По возвращению правда, ViewGroup - хonTouchEvent()
будет получать все последующие события до следующихACTION_UP
илиACTION_CANCEL
, и в большинстве случаев, сенсорные события междуACTION_DOWN
иACTION_UP
илиACTION_CANCEL
являютсяACTION_MOVE
, которые, как правило , признаются прокрутки / швырнуть жесты.Если вы вернете false из
onInterceptTouchEvent()
,onTouchEvent()
будет вызван целевой вид . Это будет повторяться для последующих сообщений, пока вы не вернете true изonInterceptTouchEvent()
.Источник: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html
источник
И Activity, и View имеют методы dispatchTouchEvent () и onTouchEvent. В ViewGroup также есть эти методы, но есть другой метод с именем onInterceptTouchEvent. Тип возврата этих методов логический, вы можете управлять маршрутом отправки через возвращаемое значение.
Отправка события в Android начинается с Activity-> ViewGroup-> View.
источник
источник
Маленький ответ:
onInterceptTouchEvent предшествует setOnTouchListener.
источник