Intereting Posts
EditText в ListView, скрытый клавиатурой при фокусировке Предупреждение установки студии Android: папка не была перемещена Как добавить пользовательский атрибут (ник) в свой тег сообщения XMPP, в Smack 4.1 Как установить шрифт Spannable object с пользовательским шрифтом Android TextInputLayout Переключение пароля не отображается в новой библиотеке поддержки Закрыть всплывающее окно кнопкой «Назад» Программно изменить значение цветового ресурса, полученного из ответа API ScrollView alawys прокручивается на дно Эта зависимость дает мне две версии одной банки. Как это исправить? Как добавить дополнительный язык для Android? Сохранение MediaController на экране в VideoView Пользовательский календарь для Android Удаление данных из ArrayList с помощью цикла For-loop Не удалось прочитать строку 1, столбец -1 из CursorWindow. Перед доступом к данным убедитесь, что курсор инициализирован правильно ADB – Android – Получение названия текущей деятельности

Android: Разница между onInterceptTouchEvent и dispatchTouchEvent?

В чем разница между onInterceptTouchEvent и dispatchTouchEvent в Android?

Согласно руководству разработчика Android, оба метода можно использовать для перехвата сенсорного события ( MotionEvent ), но в чем разница?

Как onInterceptTouchEvent , dispatchTouchEvent и onTouchEvent взаимодействуют друг с другом в иерархии представлений ( ViewGroup )?

Solutions Collecting From Web of "Android: Разница между onInterceptTouchEvent и dispatchTouchEvent?"

Лучшим местом для демистификации является исходный код. Документы крайне неадекватны в объяснении этого.

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 для обработки основных событий.

В целом его чрезмерно сложный дизайн imo, но android apis больше ориентирован на гибкость, чем простота.

Потому что это первый результат в Google. Я хочу поделиться с вами замечательным Разговором Дэйвом Смитом на Youtube: Освоение Android Touch System и слайды доступны здесь . Это дало мне хорошее глубокое понимание системы Android Touch:

Как работает Activity :

  • Activity.dispatchTouchEvent()
    • Всегда сначала называть
    • Отправляет событие в корневой вид, прикрепленный к окну
    • onTouchEvent()
      • Вызывается, если никакие представления не потребляют событие
      • Всегда нужно называть

Как обрабатывает вид :

  • View.dispatchTouchEvent()
    • Сначала отправляет событие слушателю, если существует
      • View.OnTouchListener.onTouch()
    • Если не потребляется, обрабатывает сам сенсор
      • View.onTouchEvent()

Как ViewGroup обрабатывает касание:

  • ViewGroup.dispatchTouchEvent()
    • onInterceptTouchEvent()
      • Проверьте, не должно ли это заменить детей
      • Передаёт ACTION_CANCEL активному ребенку
      • Возвращайте true однажды, потребляет все последующие события
    • Для каждого дочернего представления в обратном порядке они были добавлены
      • Если касание имеет значение (внутренний вид), child.dispatchTouchEvent()
      • Если предыдущее не обрабатывается, отправьте на следующий просмотр
    • Если дети не справляются со случаем, слушатель получает шанс
      • OnTouchListener.onTouch()
    • Если слушатель не прослушивается или не обрабатывается
      • onTouchEvent()
  • Перехваченные события перескакивают через дочерний шаг

Он также предоставляет пример кода пользовательского касания github.com/devunwired/ .

Ответ. В основном dispatchTouchEvent() вызывается на каждом уровне View чтобы определить, заинтересован ли View в продолжающемся жесте. В ViewGroup ViewGroup имеет возможность украсть события ViewGroup в ViewGroup dispatchTouchEvent() , прежде чем он вызовет dispatchTouchEvent() для детей. ViewGroup остановит только диспетчеризацию, если метод ViewGroup onInterceptTouchEvent() возвращает true. Разница заключается в том, что dispatchTouchEvent() отправляет MotionEvents а onInterceptTouchEvent сообщает, следует ли перехватывать (не отправлять MotionEvent детям) или нет (отправка детям) .

Вы можете представить, что код ViewGroup делает больше или меньше этого (очень упрощенного):

 public boolean dispatchTouchEvent(MotionEvent ev) { if(!onInterceptTouchEvent()){ for(View child : children){ if(child.dispatchTouchEvent(ev)) return true; } } return super.dispatchTouchEvent(ev); } 

Существует много путаницы в отношении этих методов, но на самом деле это не так сложно. Большая часть путаницы заключается в том, что:

  1. Если ваше представление (группа) или любое из его дочерних объектов не вернет true в onTouchEvent, dispatchTouchEvent и onInterceptTouchEvent будут ТОЛЬКО вызываться для MotionEvent.ACTION_DOWN. Без true из onTouchEvent родительский взгляд будет предполагать, что вашему представлению не требуется MotionEvents.
  2. Если ни один из дочерних элементов ViewGroup не возвращает true в onTouchEvent, onInterceptTouchEvent будет ТОЛЬКО вызываться для MotionEvent.ACTION_DOWN, даже если ваша ViewGroup возвращает true в onTouchEvent.

Порядок обработки такой:

  1. Вызывается dispatchTouchEvent.
  2. OnInterceptTouchEvent вызывается для MotionEvent.ACTION_DOWN или когда любой из дочерних элементов ViewGroup возвращается true в onTouchEvent.
  3. OnTouchEvent сначала вызывается для дочерних элементов ViewGroup, и когда ни один из детей не возвращает true, он вызывается в представлении (группе).

Если вы хотите просмотреть TouchEvents / MotionEvents, не отключая события от своих детей, вы должны сделать две вещи:

  1. Переопределить dispatchTouchEvent для предварительного просмотра события и возврата super.dispatchTouchEvent (ev);
  2. Переопределите onTouchEvent и верните true, иначе вы не получите MotionEvent, кроме MotionEvent.ACTION_DOWN.

Если вы хотите обнаружить какой-то жест как событие салфетки, не отключая другие события для своих детей, пока вы не обнаруживаете жест, вы можете сделать это следующим образом:

  1. Просмотрите MotionEvents, как описано выше, и установите флаг, когда вы обнаружили свой жест.
  2. Возвращает true в onInterceptTouchEvent, когда ваш флаг установлен для отмены обработки MotionEvent вашими детьми. Это также удобное место для сброса вашего флага, потому что onInterceptTouchEvent не будет вызываться снова до следующего MotionEvent.ACTION_DOWN.

Пример переопределений в FrameLayout (мой пример – это C #, поскольку я программирую с Xamarin Android, но логика в Java аналогична):

 public override bool DispatchTouchEvent(MotionEvent e) { // Preview the touch event to detect a swipe: switch (e.ActionMasked) { case MotionEventActions.Down: _processingSwipe = false; _touchStartPosition = e.RawX; break; case MotionEventActions.Move: if (!_processingSwipe) { float move = e.RawX - _touchStartPosition; if (move >= _swipeSize) { _processingSwipe = true; _cancelChildren = true; ProcessSwipe(); } } break; } return base.DispatchTouchEvent(e); } public override bool OnTouchEvent(MotionEvent e) { // To make sure to receive touch events, tell parent we are handling them: return true; } public override bool OnInterceptTouchEvent(MotionEvent e) { // Cancel all children when processing a swipe: if (_cancelChildren) { // Reset cancel flag here, as OnInterceptTouchEvent won't be called until the next MotionEventActions.Down: _cancelChildren = false; return true; } return false; } 

Я натолкнулся на очень интуитивное объяснение на этой веб-странице http://doandroids.com/blogs/tag/codeexample/ . Взято оттуда:

  • Boolean onTouchEvent (MotionEvent ev) – вызывается всякий раз, когда обнаружено событие касания с этим представлением в качестве цели
  • Boolean onInterceptTouchEvent (MotionEvent ev) – вызывается всякий раз, когда обнаружено событие касания с этой ViewGroup или дочерним элементом в качестве цели. Если эта функция вернёт true, MotionEvent будет перехвачен, то есть он не будет передан ребенку, а скорее будет onTouchEvent этого представления.

DispatchTouchEvent обрабатывает до onInterceptTouchEvent.

Используя этот простой пример:

  main = new LinearLayout(this){ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { System.out.println("Event - onInterceptTouchEvent"); return super.onInterceptTouchEvent(ev); //return false; //event get propagated } @Override public boolean dispatchTouchEvent(MotionEvent ev) { System.out.println("Event - dispatchTouchEvent"); return super.dispatchTouchEvent(ev); //return false; //event DONT get propagated } }; main.setBackgroundColor(Color.GRAY); main.setLayoutParams(new LinearLayout.LayoutParams(320,480)); viewA = new EditText(this); viewA.setBackgroundColor(Color.YELLOW); viewA.setTextColor(Color.BLACK); viewA.setTextSize(16); viewA.setLayoutParams(new LinearLayout.LayoutParams(320,80)); main.addView(viewA); setContentView(main); 

Вы можете видеть, что журнал будет выглядеть так:

 I/System.out(25900): Event - dispatchTouchEvent I/System.out(25900): Event - onInterceptTouchEvent 

Поэтому, если вы работаете с этими двумя обработчиками, используйте dispatchTouchEvent для обработки на первом экземпляре события, которое перейдет на onInterceptTouchEvent.

Другое отличие состоит в том, что если dispatchTouchEvent возвращает «false», событие не распространяется на дочерний элемент, в этом случае EditText, тогда как если вы вернете false в onInterceptTouchEvent, событие все равно получит отправку в EditText

Вы можете найти ответ в этом видео https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19 и следующие 3 видео. Все события касания объясняются очень хорошо, это очень ясно и полно примеров.

Следующий код в подклассе ViewGroup предотвратит получение родительскими контейнерами сенсорных событий:

  @Override public boolean dispatchTouchEvent(MotionEvent ev) { // Normal event dispatch to this container's children, ignore the return value super.dispatchTouchEvent(ev); // Always consume the event so it is not dispatched further up the chain return true; } 

Я использовал это с пользовательским оверлеем, чтобы предотвратить просмотр фоновых представлений о событиях касания.

Основное различие:

• Activity.dispatchTouchEvent (MotionEvent) – это позволяет вашей активности перехватывать все события касания до того, как они будут отправлены в окно.
• ViewGroup.onInterceptTouchEvent (MotionEvent). Это позволяет ViewGroup просматривать события по мере их отправки в дочерние представления.

Функция onInterceptTouchEvent() всегда является точкой входа для события ACTION_DOWN которое является первым событием.

Если вы хотите, чтобы ViewGroup обрабатывал этот жест, верните true из onInterceptTouchEvent() . При возврате true, onTouchEvent onTouchEvent() будет onTouchEvent() все последующие события до следующих ACTION_UP или ACTION_CANCEL , и в большинстве случаев события касания между ACTION_DOWN и ACTION_UP или ACTION_CANCEL являются ACTION_MOVE , которые обычно будут распознаваться как жесты прокрутки / перемещения.

Если вы onInterceptTouchEvent() false из onInterceptTouchEvent() , будет вызываться onInterceptTouchEvent() целевого представления. Он будет повторяться для последующих сообщений, пока вы не onInterceptTouchEvent() true из onInterceptTouchEvent() .

Источник: http://neevek.net/posts/2013/10/13/implementing-onInceptceptTouchEvent-and-onTouchEvent-for-ViewGroup.html

В Activity и View есть метод dispatchTouchEvent () и onTouchEvent.The ViewGroup тоже имеет эти методы, но имеет другой метод, называемый onInterceptTouchEvent. Тип возврата этих методов является логическим, вы можете управлять маршрутом отправки через возвращаемое значение.

Отправка события в Android начинается с Activity-> ViewGroup-> View.

Малый ответ:

OnInterceptTouchEvent появляется перед setOnTouchListener.