Intereting Posts
Android. Эффективность анимации Android HttpClient и Cookies Обнаружение максимальной поддержки разрешения видео для мобильного устройства на быстродействующем веб-сайте Android Build – эмулятор, застрявший на логотипе Android Ресурсы по вспомогательному модулю sibling, проект Gradle Android-приложение вылетает с сигналом SIGABRT 6 только при отладке Eclipse Не удалось найти дизайнера пользовательского интерфейса в новой Android Studio Перенесите InputStream на другую службу (через границы процесса) с помощью ParcelFileDescriptor.createPipe (), которая не работает с «EBADF (Bad file number)» Copy-paste не работает в Android Studio на Mac Android spinner устанавливает текст по умолчанию Выбор TextView setScaleX () / setScaleY () и setTextIsSelectable (true) Обработка перехода нескольких геообъектов с общей областью Поддержка Grid Layout в API android API 10 NoClassDefFoundError ниже SDK 21 Слишком большое приложение? Невозможно выполнить dex: невозможно объединить новый индекс в инструкцию, отличную от jumbo

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.