El mejor lugar para desmitificar esto es el código fuente. Los documentos son lamentablemente inadecuados para explicar esto.
dispatchTouchEvent se define realmente en Activity, View y ViewGroup. Piense en ello como un controlador que decide cómo enrutar los eventos táctiles.
Por ejemplo, el caso más simple es el de View.dispatchTouchEvent que enrutará el evento táctil a OnTouchListener.onTouch si está definido o al método de extensión onTouchEvent .
Para ViewGroup.dispatchTouchEvent las cosas son mucho más complicadas. Necesita averiguar cuál de sus vistas secundarias debería recibir el evento (llamando a child.dispatchTouchEvent). Esto es básicamente un algoritmo de prueba de éxito en el que descubres qué rectángulo delimitador de la vista secundaria contiene las coordenadas del punto de contacto.
Pero antes de que pueda enviar el evento a la vista secundaria apropiada, el padre puede espiar y / o interceptar el evento todos juntos. Para eso está onInterceptTouchEvent . Por lo tanto, llama a este método primero antes de hacer la prueba de impacto y si el evento fue secuestrado (devolviendo true desde onInterceptTouchEvent) envía un ACTION_CANCEL a las vistas secundarias para que puedan abandonar su procesamiento de eventos táctiles (de eventos táctiles anteriores) y de ahí en adelante Todos los eventos táctiles en el nivel primario se envían a onTouchListener.onTouch (si está definido) o onTouchEvent (). También en ese caso, onInterceptTouchEvent nunca se llama de nuevo.
¿Desearía incluso anular [Activity | ViewGroup | View] .dispatchTouchEvent? A menos que esté haciendo un enrutamiento personalizado, probablemente no debería hacerlo.
Los principales métodos de extensión son ViewGroup.onInterceptTouchEvent si desea espiar y / o interceptar eventos táctiles en el nivel primario y View.onTouchListener / View.onTouchEvent para el manejo de eventos principales.
En general, su diseño excesivamente complicado, pero las API de Android se inclinan más hacia la flexibilidad que la simplicidad.
Porque este es el primer resultado en Google. Quiero compartir con ustedes una gran charla de Dave Smith en Youtube: Dominar el sistema táctil de Android y las diapositivas están disponibles aquí . Me dio una buena comprensión profunda sobre el sistema Android Touch:
Cómo maneja la actividad el tacto:
Cómo maneja la vista táctil:
Cómo un ViewGroup maneja el tacto:
También proporciona un código de ejemplo de toque personalizado en github.com/devunwired/ .
Respuesta: Básicamente
dispatchTouchEvent()
se invoca en cadaView
capa para determinar si aView
está interesado en un gesto en curso. En unaViewGroup
laViewGroup
tiene la capacidad de robar los eventos de toque en sudispatchTouchEvent()
-method, antes de que llamaríadispatchTouchEvent()
a los niños. losViewGroup
solo detendría el envío si elViewGroup
onInterceptTouchEvent()
método devuelve verdadero. La diferencia es quedispatchTouchEvent()
está enviandoMotionEvents
yonInterceptTouchEvent
dice si debe interceptar (no enviarMotionEvent
a los niños) o no (enviar a los niños) .Podrías imaginar el código de un ViewGroup haciendo más o menos esto (muy simplificado):
fuente
Respuesta suplementaria
Aquí hay algunos suplementos visuales para las otras respuestas. Mi respuesta completa está aquí .
El
dispatchTouchEvent()
método de unViewGroup
utilizaonInterceptTouchEvent()
para elegir si debe manejar inmediatamente el evento táctil (cononTouchEvent()
) o continuar notificando losdispatchTouchEvent()
métodos de sus hijos.fuente
Hay mucha confusión sobre estos métodos, pero en realidad no es tan complicado. La mayor parte de la confusión se debe a que:
View/ViewGroup
o alguno de sus hijos no devuelve verdaderoonTouchEvent
,dispatchTouchEvent
yonInterceptTouchEvent
SOLO se le pediráMotionEvent.ACTION_DOWN
. Sin un verdadero deonTouchEvent
, la vista principal asumirá que su vista no necesita los MotionEvents.MotionEvent.ACTION_DOWN
, incluso si su ViewGroup devuelve true enonTouchEvent
.La orden de procesamiento es así:
dispatchTouchEvent
se llama.onInterceptTouchEvent
se llama paraMotionEvent.ACTION_DOWN
o cuando alguno de los elementos secundarios de ViewGroup devuelve true enonTouchEvent
.onTouchEvent
primero se llama a los hijos del ViewGroup y cuando ninguno de los hijos devuelve verdadero, se llama alView/ViewGroup
.Si quieres previsualizar
TouchEvents/MotionEvents
sin deshabilitar los eventos en sus hijos, debe hacer dos cosas:dispatchTouchEvent
para obtener una vista previa del evento y volversuper.dispatchTouchEvent(ev)
;onTouchEvent
y devolver verdadero, de lo contrario no obtendráMotionEvent
exceptoMotionEvent.ACTION_DOWN
.Si desea detectar algún gesto como un evento de deslizamiento, sin deshabilitar otros eventos en sus hijos, siempre que no haya detectado el gesto, puede hacerlo así:
onInterceptTouchEvent
cuando su bandera está configurada para cancelar el procesamiento de MotionEvent por parte de sus hijos. Este también es un lugar conveniente para restablecer su bandera, porque onInterceptTouchEvent no se volverá a llamar hasta la próximaMotionEvent.ACTION_DOWN
.Ejemplo de anulaciones en a
FrameLayout
(mi ejemplo en C # es porque estoy programando con Xamarin Android, pero la lógica es la misma en Java):fuente
Encontré una explicación muy intuitiva en esta página web http://doandroids.com/blogs/tag/codeexample/ . Tomado de allí:
fuente
dispatchTouchEvent maneja antes de onInterceptTouchEvent.
Usando este simple ejemplo:
Puede ver que el registro será así:
Entonces, en caso de que esté trabajando con estos 2 controladores, use dispatchTouchEvent para manejar en primera instancia el evento, que irá a onInterceptTouchEvent.
Otra diferencia es que si dispatchTouchEvent devuelve 'false', el evento no se propaga al elemento secundario, en este caso EditText, mientras que si devuelve false en onInterceptTouchEvent el evento aún se envía a EditText
fuente
Respuesta corta:
dispatchTouchEvent()
se llamará primero lugar.Consejo breve: no debe anular,
dispatchTouchEvent()
ya que es difícil de controlar, a veces puede ralentizar su rendimiento. En mi humilde opinión, sugiero anulaciónonInterceptTouchEvent()
.Debido a que la mayoría de las respuestas mencionan claramente sobre el evento táctil de flujo en la actividad / vista grupo / vista, solo agrego más detalles sobre el código en estos métodos en
ViewGroup
(ignorandodispatchTouchEvent()
):onInterceptTouchEvent()
se llamará primero, el evento ACTION se llamará respectivamente hacia abajo -> mover -> hacia arriba. Hay 2 casos:Si devuelve falso en 3 casos (ACTION_DOWN, ACTION_MOVE, ACTION_UP), se considerará que el padre no necesitará este evento táctil , por lo que
onTouch()
los padres nunca llaman , peroonTouch()
los niños llamarán en su lugar ; Sin embargo, tenga en cuenta:onInterceptTouchEvent()
todavía siguen recibiendo eventos táctiles, siempre y cuando sus hijos no lo llamanrequestDisallowInterceptTouchEvent(true)
.onTouch()
los padres.Viceversa, si devuelve verdadero , el padre robará este evento táctil inmediatamente y
onInterceptTouchEvent()
se detendrá de inmediato, en lugaronTouch()
de que se llame a los padres y todos losonTouch()
niños recibirán el último evento de acción: ACTION_CANCEL (por lo tanto, significa que los padres robaron evento táctil, y los niños no pueden manejarlo desde entonces). El flujo deonInterceptTouchEvent()
retorno falso es normal, pero hay una pequeña confusión con el caso de retorno verdadero, así que lo enumero aquí:onTouch()
de los padres recibirán ACTION_DOWN nuevamente y las siguientes acciones (ACTION_MOVE, ACTION_UP).onTouch()
de los padres recibirán el próximo ACTION_MOVE (no el mismo ACTION_MOVE enonInterceptTouchEvent()
) y las siguientes acciones (ACTION_MOVE, ACTION_UP).onTouch()
los padres NO llamarán en absoluto ya que es demasiado tarde para que los padres roben el evento táctil.Una cosa más importante es que ACTION_DOWN del evento
onTouch()
determinará si la vista desea recibir más acciones de ese evento o no. Si la vista se vuelve verdadera en ACTION_DOWNonTouch()
, significa que está dispuesta a recibir más acción de ese evento. De lo contrario, devolver falso en ACTION_DOWNonTouch()
implicará que la vista no recibirá más acciones de ese evento.fuente
Puede encontrar la respuesta en este video https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19 y los siguientes 3 videos. Todos los eventos táctiles se explican muy bien, es muy claro y está lleno de ejemplos.
fuente
El siguiente código dentro de una subclase de ViewGroup evitaría que sus contenedores principales reciban eventos táctiles:
Utilicé esto con una superposición personalizada para evitar que las vistas de fondo respondan a eventos táctiles.
fuente
La principal diferencia :
fuente
ViewGroup's
onInterceptTouchEvent()
es siempre el punto de entrada para elACTION_DOWN
evento, que es el primer evento en ocurrir.Si desea que ViewGroup procese este gesto, devuelva true desde
onInterceptTouchEvent()
. Al volver verdadero, ViewGroup'sonTouchEvent()
recibirá todos los eventos posteriores hasta el próximoACTION_UP
oACTION_CANCEL
, y en la mayoría de los casos, los eventos táctiles entreACTION_DOWN
yACTION_UP
oACTION_CANCEL
sonACTION_MOVE
, que normalmente se reconocerán como gestos de desplazamiento / lanzamiento.Si devuelve falso desde
onInterceptTouchEvent()
,onTouchEvent()
se llamará a la vista de destino . Se repetirá para los mensajes posteriores hasta que regrese verdadero deonInterceptTouchEvent()
.Fuente: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html
fuente
Tanto Activity como View tienen el método dispatchTouchEvent () y onTouchEvent. ViewGroup también tiene estos métodos, pero tiene otro método llamado onInterceptTouchEvent. El tipo de retorno de esos métodos es booleano, puede controlar la ruta de envío a través del valor de retorno.
El envío de eventos en Android comienza desde Actividad-> Ver Grupo-> Ver.
fuente
fuente
Pequeña respuesta:
onInterceptTouchEvent viene antes de setOnTouchListener.
fuente