usar studio propiedad metodo eventos como capturar boton atributo java android event-handling event-listener android-touch-event

java - propiedad - onclick android studio



Android: ¿Diferencia entre onInterceptTouchEvent y dispatchTouchEvent? (14)

Respuesta suplementaria

Aquí hay algunos suplementos visuales a las otras respuestas. Mi respuesta completa está here .

El método dispatchTouchEvent() de un ViewGroup usa onInterceptTouchEvent() para elegir si debe controlar inmediatamente el evento táctil (con onTouchEvent() ) o continuar notificando los métodos dispatchTouchEvent() de sus elementos onTouchEvent() .

¿Cuál es la diferencia entre onInterceptTouchEvent y dispatchTouchEvent en Android?

De acuerdo con la guía del desarrollador de Android, ambos métodos pueden usarse para interceptar un evento táctil ( MotionEvent ), pero ¿cuál es la diferencia?

¿Cómo interactúan entre onInterceptTouchEvent , dispatchTouchEvent y onTouchEvent dentro de una jerarquía de Vistas ( ViewGroup )?


El mejor lugar para desmitificar esto es el código fuente. Los doctores 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. Debe averiguar cuál de sus vistas secundarias debería obtener el evento (llamando a child.dispatchTouchEvent). Básicamente, este es un algoritmo de prueba de aciertos en el que se determina 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. Esto es para lo que está onInterceptTouchEvent . Por lo tanto, primero llama a este método antes de realizar la prueba de aciertos 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 vuelve a llamar.

¿Desearía incluso anular [Activity | ViewGroup | View] .dispatchTouchEvent? A menos que esté haciendo un enrutamiento personalizado, probablemente no debería.

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 demasiado complicado, pero las API de Android se inclinan más hacia la flexibilidad que la simplicidad.


El objeto onInterceptTouchEvent() de onInterceptTouchEvent() es siempre el punto de entrada para el evento ACTION_DOWN , que es el primer evento en ocurrir.

Si desea que ViewGroup procese este gesto, devuelva true desde onInterceptTouchEvent() . Al regresar verdadero, onTouchEvent onTouchEvent() de onTouchEvent() recibirá todos los eventos subsiguientes hasta el próximo ACTION_UP o ACTION_CANCEL , y en la mayoría de los casos, los eventos táctiles entre ACTION_DOWN y ACTION_UP o ACTION_CANCEL son ACTION_MOVE , que normalmente se reconocerán como gestos de desplazamiento / desplazamiento.

Si devuelve falso desde onInterceptTouchEvent() , se onInterceptTouchEvent() a onInterceptTouchEvent() la vista de onTouchEvent() . Se repetirá para los mensajes subsiguientes hasta que devuelva verdadero desde onInterceptTouchEvent() .

Fuente: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html


El siguiente código dentro de una subclase de ViewGroup evitaría que sus contenedores principales reciban eventos táctiles:

@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; }

Usé esto con una superposición personalizada para evitar que las vistas de fondo respondan a eventos táctiles.


Hay mucha confusión sobre estos métodos, pero en realidad no es tan complicado. La mayor parte de la confusión es porque:

  1. Si su View/ViewGroup o cualquiera de sus hijos no devuelven verdadero en onTouchEvent , dispatchTouchEvent y onInterceptTouchEvent SOLAMENTE serán llamados para MotionEvent.ACTION_DOWN . Sin un true de onTouchEvent , la vista principal asumirá que su vista no necesita los MotionEvents.
  2. Cuando ninguno de los hijos de un ViewGroup devuelve true en onTouchEvent, onInterceptTouchEvent SOLAMENTE se llamará para MotionEvent.ACTION_DOWN , incluso si su ViewGroup devuelve true en onTouchEvent .

El orden de procesamiento es así:

  1. Se llama dispatchTouchEvent .
  2. onInterceptTouchEvent se llama para MotionEvent.ACTION_DOWN o cuando alguno de los hijos de ViewGroup devuelve true en onTouchEvent .
  3. onTouchEvent se llama primero en los hijos de ViewGroup y cuando ninguno de los hijos devuelve true, se llama en View/ViewGroup .

Si desea obtener TouchEvents/MotionEvents vista previa de TouchEvents/MotionEvents sin desactivar los eventos en sus hijos, debe hacer dos cosas:

  1. Reemplace dispatchTouchEvent para obtener una vista previa del evento y devolver super.dispatchTouchEvent(ev) ;
  2. Sobrescriba onTouchEvent y devuelva verdadero, de lo contrario no obtendrá ningún MotionEvent excepto MotionEvent.ACTION_DOWN .

Si desea detectar algún gesto como un evento de barrido, sin deshabilitar otros eventos en sus hijos mientras no detecte el gesto, puede hacerlo de la siguiente manera:

  1. Previsualice los MotionEvents como se describe anteriormente y establezca una marca cuando detecte su gesto.
  2. Devuelva true en onInterceptTouchEvent cuando su onInterceptTouchEvent esté configurada para cancelar el procesamiento de MotionEvent por parte de sus hijos. Este también es un lugar conveniente para restablecer su marca, ya que no se llamará a MotionEvent.ACTION_DOWN hasta el siguiente MotionEvent.ACTION_DOWN .

Ejemplo de anulaciones en un FrameLayout (mi ejemplo en C # es como estoy programando con Xamarin Android, pero la lógica es la misma en 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; }


La principal diferencia :

• Activity.dispatchTouchEvent (MotionEvent): esto permite que su actividad intercepte todos los eventos táctiles antes de que se envíen a la ventana.
• ViewGroup.onInterceptTouchEvent (MotionEvent): esto permite que ViewGroup vea eventos a medida que se envían a vistas secundarias.


Me encontré con una explicación muy intuitiva en esta página web http://doandroids.com/blogs/tag/codeexample/ . Tomado de allí:

  • onTouchEvent booleano (MotionEvent ev): se llama cuando se detecta un evento táctil con esta vista como objetivo
  • boolean onInterceptTouchEvent (MotionEvent ev): se llama cada vez que se detecta un evento táctil con este ViewGroup o un elemento secundario como objetivo. Si esta función devuelve verdadero, el MotionEvent será interceptado, lo que significa que no se transmitirá al niño, sino al onTouchEvent de esta Vista.

Pequeña respuesta:

onInterceptTouchEvent viene antes de setOnTouchListener.


Porque este es el primer resultado en Google. Quiero compartir con ustedes una excelente charla de Dave Smith en Youtube: dominar el sistema táctil de Android y las diapositivas están disponibles here . Me dio una buena comprensión profunda sobre el sistema táctil de Android:

Cómo maneja la actividad el tacto:

  • Activity.dispatchTouchEvent()
    • Siempre primero en ser llamado
    • Envía evento a la vista de raíz adjunta a la ventana
    • onTouchEvent()
      • Llamado si no hay vistas consumen el evento.
      • Siempre último en ser llamado

Cómo maneja la vista el tacto:

  • View.dispatchTouchEvent()
    • Envía el evento al oyente primero, si existe
      • View.OnTouchListener.onTouch()
    • Si no se consume, se procesa el propio toque.
      • View.onTouchEvent()

Cómo un grupo de vista maneja el tacto:

  • ViewGroup.dispatchTouchEvent()
    • onInterceptTouchEvent()
      • Compruebe si debería reemplazar a los niños
      • Pasa ACTION_CANCEL al niño activo
      • Devuelve true una vez, consume todos los eventos posteriores.
    • Para cada vista de niño, en orden inverso se agregaron
      • Si el toque es relevante (vista interior), child.dispatchTouchEvent()
      • Si no es manejado por el anterior, despacha a la siguiente vista
    • Si ningún niño maneja el evento, el oyente tiene una oportunidad
      • OnTouchListener.onTouch()
    • Si no hay oyente, o no se maneja
      • onTouchEvent()
  • Los eventos interceptados saltan sobre el paso del niño.

También proporciona código de ejemplo de toque personalizado en github.com/devunwired/ .

Respuesta: Básicamente, se llama a dispatchTouchEvent() en cada capa de View para determinar si una View está interesada en un gesto en curso. En un ViewGroup el ViewGroup tiene la capacidad de robar los eventos táctiles en su método dispatchTouchEvent() , antes de llamar a dispatchTouchEvent() en los niños. ViewGroup solo detendría el envío si ViewGroup onInterceptTouchEvent() -method devuelve true. La diferencia es que dispatchTouchEvent() está enviando MotionEvents y onInterceptTouchEvent le dice si debe interceptar (no enviar el MotionEvent 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):

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



Tanto Activity como View tienen el método dispatchTouchEvent () y onTouchEvent. El 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.


dispatchTouchEvent maneja antes de onInterceptTouchEvent.

Usando este sencillo ejemplo:

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);

Puedes ver que el log será como:

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

Entonces, en caso de que esté trabajando con estos 2 manejadores, utilice dispatchTouchEvent para manejar en primera instancia el evento, que irá a onInterceptTouchEvent.

Otra diferencia es que si dispatchTouchEvent devuelve ''falso'', el evento no se propaga al hijo, en este caso el Texto de edición, mientras que si devuelve falso en onInterceptTouchEvent, el evento aún se enviará al Texto de edición


Respuesta corta: se dispatchTouchEvent() primer 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 anular onInterceptTouchEvent() .

Debido a que la mayoría de las respuestas mencionan claramente el evento de toque de flujo en la actividad / vista de grupo / vista, solo agrego más detalles sobre el código de estos métodos en ViewGroup (ignorando dispatchTouchEvent() ):

onInterceptTouchEvent() se llamará primero, el evento ACTION se llamará respectivamente down -> move -> up. Hay 2 casos:

  1. Si devuelve falso en 3 casos (ACTION_DOWN, ACTION_MOVE, ACTION_UP), considerará que el padre no necesitará este evento táctil , por lo que onTouch() de los padres nunca llama , pero onTouch() de los niños llamará en su lugar ; Sin embargo, tenga en cuenta:

    • El onInterceptTouchEvent() aún continúa recibiendo el evento táctil, siempre que sus hijos no llamen a requestDisallowInterceptTouchEvent(true) .
    • Si no hay niños que reciban ese evento (puede ocurrir en 2 casos: no hay niños en la posición que los usuarios tocan, o si hay niños pero devuelve falso en ACTION_DOWN), los padres enviarán ese evento a onTouch() del los padres
  2. A la inversa, si devuelve verdadero , el padre robará este evento táctil de inmediato, y onInterceptTouchEvent() se detendrá de inmediato, en onTouch() lugar se onTouch() de los padres, así como a todos los onTouch() , recibirán el último evento de acción - ACTION_CANCEL (por lo tanto, significa que los padres robaron el evento táctil y los niños no pueden manejarlo desde ese momento). El flujo de onInterceptTouchEvent() devuelve false es normal, pero hay una pequeña confusión con return true case, por lo que lo enumero aquí:

    • Devuelva verdadero en ACTION_DOWN, onTouch() de los padres recibirá de nuevo ACTION_DOWN y las siguientes acciones (ACTION_MOVE, ACTION_UP).
    • Devuelva verdadero en ACTION_MOVE, onTouch() de los padres recibirá el siguiente ACTION_MOVE (no es el mismo ACTION_MOVE en onInterceptTouchEvent() ) y las siguientes acciones (ACTION_MOVE, ACTION_UP).
    • Devuelva true en ACTION_UP, onTouch() de los padres NO llamará, ya que es demasiado tarde para que los padres roben el evento de toque.

Una cosa más importante es ACTION_DOWN del evento en onTouch() determinará si la vista desea recibir más acción de ese evento o no. Si la vista devuelve verdadero en ACTION_DOWN en onTouch() , significa que la vista está dispuesta a recibir más acción de ese evento. De lo contrario, devolver falso en ACTION_DOWN en onTouch() implicará que la vista no recibirá más acciones de ese evento.


public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume =false; if(onInterceptTouchEvent(ev){ consume = onTouchEvent(ev); }else{ consume = child.dispatchTouchEvent(ev); } }