Capturar Eventos Touch en una Activity o View en Android

Buenas tardes, en esta entrada vamos a ver un punto importante e interesante en Android, los denominados Eventos Touch.

Este tipo de eventos se dan cuando el usuario interacciona con la pantalla del terminal, y con esta entrada aprenderemos a conocer que eventos se dán en cada momento.


Vamos a ponernos manos a la obra:

  • Creación del Proyecto

    Para comenzar vamos a ir a File -> New -> Android Application Project. Si por algún caso no vemos esta opción disponible, nos vamos a dirigir a “Other”, donde al pulsar nos aparecerá una ventana para buscar en una lista. En el apartado de Android podremos encontrar “Android Application Project”. Sin embargo, podemos introducir la palabra “Android” en la caja de texto para filtrar los resultados y que nos sea mas fácil encontrarlo.

    Una vez encontremos la opción y pulsemos sobre ella, nos aparecerá el asistente de creación de un proyecto Android, en el cual vamos a darle un nombre, en mi caso lo he llamado “EjemploCapturarGesto”, pero podeis poner el nombre que deseeis. El resto de las opciones podeis dejarlas tal como están.

    Según vamos avanzando por el asistente, nos encontraremos con una ventana en la que podremos configurar el nombre de nuestra Activity, en mi caso la he llamado “GesturesActivity”, aunque podeis poner también el que querais. Su archivo layout, se llamará “activity_gestures.xml”.

    Una vez acabemos el asistente, podremos comenzar con la construcción de nuestra aplicación.

  • GesturesActivity

    Esta será la Activity que se nos creará por defecto al crear nuestro proyecto. En ella implementaremos lo necesario para conocer los diferentes eventos que se están dando sobre nuestra pantalla. Su archivo layout, sin embargo, no lo vamos a tocar, ya que para esta prueba, no necesitamos ninguna interfaz gráfica especial. Sin embargo si queremos, podemos poner un TextView para que no quede una pantalla en blanco totalmente. A continuación vemos el código del archivo activity_gestures.xml:

    		<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    		    xmlns:tools="http://schemas.android.com/tools"
    		    android:layout_width="match_parent"
    		    android:layout_height="match_parent"
    		    tools:context=".GesturesActivity"
    		    android:gravity="center_vertical|center_horizontal" >
    		
    		    <TextView
    		        android:id="@+id/tvText"
    		        android:layout_width="wrap_content"
    		        android:layout_height="wrap_content"
    		        android:text="Ejemplo Gestures"/>
    		
    		</RelativeLayout>
    		

    Como vemos, tenemos un TextView para no dejarlo vacio, pero luego podemos usarlo para detectar estos eventos en el.

    Por otro lado, el código de nuestra Activity tiene la implementación para que podamos saber que eventos ocurren en nuestra pantalla. Vamos a ver el código:

    		package sekth.droid.gestures;
    
    		import android.app.Activity;
    		import android.os.Bundle;
    		import android.support.v4.view.MotionEventCompat;
    		import android.util.Log;
    		import android.view.MotionEvent;
    		import android.view.View;
    		import android.widget.TextView;
    		
    		public class GesturesActivity extends Activity {
    		
    			public static final String DEBUG_TAG = "GesturesActivity";
    		
    			@Override
    			protected void onCreate(Bundle savedInstanceState) {
    				super.onCreate(savedInstanceState);
    				setContentView(R.layout.activity_gestures);
    		
    			}
    			
    			@Override
    			public boolean onTouchEvent(MotionEvent event) {
    				// TODO Auto-generated method stub
    		
    				int action = MotionEventCompat.getActionMasked(event);
    		
    				switch (action) {
    				case (MotionEvent.ACTION_DOWN):
    					Log.d(DEBUG_TAG, "La accion ha sido ABAJO");
    					return true;
    				case (MotionEvent.ACTION_MOVE):
    					Log.d(DEBUG_TAG, "La acción ha sido MOVER");
    					return true;
    				case (MotionEvent.ACTION_UP):
    					Log.d(DEBUG_TAG, "La acción ha sido ARRIBA");
    					return true;
    				case (MotionEvent.ACTION_CANCEL):
    					Log.d(DEBUG_TAG, "La accion ha sido CANCEL");
    					return true;
    				case (MotionEvent.ACTION_OUTSIDE):
    					Log.d(DEBUG_TAG,
    							"La accion ha sido fuera del elemento de la pantalla");
    					return true;
    				default:
    					return super.onTouchEvent(event);
    				}
    			}
    		}
    		

    Como podemos ver, en nuestro método onCreate no hacemos absolutamente nada, sino que vamos a sustituid el método onTouchEvent(), el cuál recibe como parámetro un objeto de la clase MotionEvent que usaremos para extraer el tipo de evento que se ha registrado.

    Para ello, hacemos uso del método getActionMasked() de la clase MotionEventCompat que reside en el paquete de soporte. Este método, el cuál acepta como argumento un objeto de la clase MotionEvent nos retornará un int, con el cuál podremos luego analizar el tipo de evento realizado. Vamos a analizar solamente 5 tipos de acciones:

    • ACTION_DOWN:

      Este evento se dá cuando pulsamos la pantalla, es decir, presionamos la pantalla y no movemos el puntero hacia ningún lado.

    • ACTION_MOVE:

      Este evento se dá cuando tras pulsar la pantalla, procedemos a mover el puntero por ella, es decir, cuando hagamos esto surgirán 2 eventos, el ACTION_DOWN y a continuación al mover el puntero aparecerá el evento ACTION_MOVE.

    • ACTION_UP:

      Este evento se dá cuando levantamos el dedo o puntero de la pantalla, para que se dé este evento debe haberse dado anteriormente el evento ACTION_DOWN.

    • ACTION_CANCEL:

      Este evento se dá cuando el gesto actual ha sido abortado y no recibamos ningún punto mas de el. En este ejemplo no nos surgirá este evento, pero es bueno considerarlo en futuras implementaciones, ya que se puede tratar como un ACTION_UP pero sin realizar tareas que normalmente realizaríamos.

    • ACTION_OUTSIDE:

      Este evento se dá cuando el evento ocurre fuera de los límites normales de un elemento de la UI.

Con esta pequeña implementación ya podemos saber cuando ocurren los 3 eventos principales sobre la pantalla, aunque se pueden sacar muchos mas valores del objeto event, pero en esta entrada nos hemos dedicado en un principio a conocer cuando se dán ciertos tipos de gestos.

Sin embargo, en esta implementación que hemos hecho registra todos los eventos en la totalidad de la Activity. En el caso de que queramos aplicarla solo a un elemento de una View (en nuestro caso, el TextView) podemos registrar un OnTouchListener en la View que necesitemos. Para ello vamos a registrarlo en el TextView que teníamos de manera muy facil:

package sekth.droid.gestures;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class GesturesActivity extends Activity {

	public static final String DEBUG_TAG = "GesturesActivity";
	private TextView tvTexto;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_gestures);

		tvTexto = (TextView) findViewById(R.id.tvText);
		tvTexto.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub

				int action = MotionEventCompat.getActionMasked(event);

				switch (action) {
				case (MotionEvent.ACTION_DOWN):
					Log.d(DEBUG_TAG, "La accion ha sido ABAJO");
					return true;
				case (MotionEvent.ACTION_MOVE):
					Log.d(DEBUG_TAG, "La acción ha sido MOVER");
					return true;
				case (MotionEvent.ACTION_UP):
					Log.d(DEBUG_TAG, "La acción ha sido ARRIBA");
					return true;
				case (MotionEvent.ACTION_CANCEL):
					Log.d(DEBUG_TAG, "La accion ha sido CANCEL");
					return true;
				case (MotionEvent.ACTION_OUTSIDE):
					Log.d(DEBUG_TAG,
							"La accion ha sido fuera del elemento de la pantalla");
					return true;
				default:
					return true;
				}
			}
		});
	}
}

Como vemos ahora si pulsamos fuera de la parte que ocupa el TextView, no se registran movimientos en el LogCat, sino solo cuando pulsamos en el TextView.

A continuación vemos un pequeño video en el que vemos el LogCat y los eventos con la pantalla del emulador:



Con esta entrada hemos visto como conocer los gestos mas comunes que se dán cuando el usuario interacciona en la pantalla, que siempre podemos avanzar en cada uno de ellos para realizar diferentes acciones.

El código del ejemplo se puede descargar de aqui.

Sin más, cualquier aporte o corrección será bienvenido.

Saludos!!!

  • Aclaraste mis dudas con respecto esto. Gracias!

  • yipicaio

    hola,
    y si quisieramos un botón que independientemente de donde estuvo el dedo (si estuvo up or down) si el dedo pasa por el boton este se enciende?

    en otras palabras, hay un método que detecte el paso del dedo sobre un grafico y lo active?
    notese que digo el paso, ni click, ni tab, ni gesture.

    gracias.