Cómo detectar gestos comunes

Prueba el método de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Aprende a usar el control táctil y la entrada en Compose.

Un gesto táctil se produce cuando un usuario coloca uno o más dedos en el pantalla táctil, y tu app interpretará este patrón de toques como un gesto. Hay hay dos fases en la detección de gestos:

  1. Recopilación de datos de eventos táctiles
  2. Interpretar los datos para determinar si cumplen con los criterios del gestos que admite tu app.

Clases de AndroidX

En los ejemplos de este documento, se usa el GestureDetectorCompat y MotionEventCompat . Estas clases se encuentran en el repositorio AndroidX Biblioteca. Usa clases de AndroidX cuando sea posible para brindar compatibilidad con dispositivos anteriores. MotionEventCompat no reemplaza al MotionEvent . En cambio, proporciona métodos de utilidades estáticos a los que pasas tu MotionEvent para recibir la acción asociada con ese para cada evento.

Cómo recopilar datos

Cuando un usuario coloca uno o más dedos en la pantalla, se activa devolución de llamada onTouchEvent() en la vista que recibe los eventos táctiles. Para cada secuencia de contacto eventos, como la posición, la presión, el tamaño y la adición de otro, dedo, que se identifica como un gesto, onTouchEvent() es se activó varias veces.

El gesto comienza cuando el usuario toca la pantalla por primera vez y continúa como sistema rastrea la posición del dedo o los dedos del usuario y finaliza capturar el evento final del último dedo del usuario al salir de la pantalla A lo largo de esta interacción, el MotionEvent entregó a onTouchEvent() proporciona los detalles de cada interacción. Tu app puede usar los datos proporcionados por el MotionEvent para determinar si un importante que realmente importa.

Cómo capturar eventos táctiles para objetos Activity o View

Para interceptar eventos táctiles en un Activity o View, anula la devolución de llamada onTouchEvent().

El siguiente fragmento de código usa getAction() para extraer la acción que realiza el usuario del parámetro event. Esto te proporciona los datos sin procesar que necesitas para determinar si un gesto que te interesa ocurre.

Kotlin

class MainActivity : Activity() {
    ...
    // This example shows an Activity. You can use the same approach if you are 
    // subclassing a View.
    override fun onTouchEvent(event: MotionEvent): Boolean {
        return when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(DEBUG_TAG, "Action was DOWN")
                true
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(DEBUG_TAG, "Action was MOVE")
                true
            }
            MotionEvent.ACTION_UP -> {
                Log.d(DEBUG_TAG, "Action was UP")
                true
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.d(DEBUG_TAG, "Action was CANCEL")
                true
            }
            MotionEvent.ACTION_OUTSIDE -> {
                Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element")
                true
            }
            else -> super.onTouchEvent(event)
        }
    }
}

Java

public class MainActivity extends Activity {
...
// This example shows an Activity. You can use the same approach if you are
// subclassing a View.
@Override
public boolean onTouchEvent(MotionEvent event){
    switch(event.getAction()) {
        case (MotionEvent.ACTION_DOWN) :
            Log.d(DEBUG_TAG,"Action was DOWN");
            return true;
        case (MotionEvent.ACTION_MOVE) :
            Log.d(DEBUG_TAG,"Action was MOVE");
            return true;
        case (MotionEvent.ACTION_UP) :
            Log.d(DEBUG_TAG,"Action was UP");
            return true;
        case (MotionEvent.ACTION_CANCEL) :
            Log.d(DEBUG_TAG,"Action was CANCEL");
            return true;
        case (MotionEvent.ACTION_OUTSIDE) :
            Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element");
            return true;
        default :
            return super.onTouchEvent(event);
    }
}

Este código produce mensajes como los siguientes en Logcat a medida que el usuario presiona: toques y mantiene y arrastra:

GESTURES D   Action was DOWN
GESTURES D   Action was UP
GESTURES D   Action was MOVE

Para gestos personalizados, puedes hacer tu propio procesamiento en estos eventos determinar si representan un gesto que necesitas controlar. Sin embargo, si tus usa gestos comunes, como tocar dos veces, tocar y ejecutar, arrastrar, etcétera, puedes aprovechar la GestureDetector . GestureDetector facilita la detección de problemas sin procesar los eventos táctiles individuales. Este es que se explica con más detalle en Detecta gestos.

Cómo capturar eventos táctiles para una sola vista

Como alternativa a onTouchEvent(), puedes adjuntar un View.OnTouchListener objeto a cualquier View con el comando setOnTouchListener() . Esto permite escuchar eventos táctiles sin subclasificar un View existente, como se muestra en el siguiente ejemplo:

Kotlin

findViewById<View>(R.id.my_view).setOnTouchListener { v, event ->
    // Respond to touch events.
    true
}

Java

View myView = findViewById(R.id.my_view);
myView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent event) {
        // Respond to touch events.
        return true;
    }
});

Ten cuidado de no crear un objeto de escucha que muestre false para el ACTION_DOWN evento. Si haces esto, el objeto de escucha no se llama para la ejecución ACTION_MOVE y Secuencia ACTION_UP de eventos. Esto se debe a que ACTION_DOWN es el punto de partida para todos eventos táctiles.

Si estás creando una vista personalizada, puedes anular onTouchEvent(), como se describió antes.

Cómo detectar gestos

Android proporciona la clase GestureDetector para detectar expresiones y gestos clave. Algunos de los gestos que admite son: onDown(), onLongPress(), y onFling() Puedes usar GestureDetector junto con el elemento onTouchEvent() descrito anteriormente.

Cómo detectar todos los gestos compatibles

Cuando creas una instancia de un objeto GestureDetectorCompat, uno de los de parámetros que toma es una clase que implementa la GestureDetector.OnGestureListener interfaz de usuario. GestureDetector.OnGestureListener notifica a los usuarios cuando un que ocurra un evento táctil en particular. Para que tus GestureDetector para recibir eventos, anular la vista o método onTouchEvent() de la actividad y pasar todos los eventos observados a la instancia del detector.

En el siguiente fragmento, se muestra un valor de true del elemento métodos individuales on<TouchEvent> indica que el evento táctil. Un valor de retorno de false pasa eventos. por la pila de vistas hasta que el toque se controle con éxito.

Si ejecutas el siguiente fragmento en una app de prueba, puedes tener una idea de cómo acciones se activan cuando interactúas con la pantalla táctil y lo que el contenido de MotionEvent es para cada evento táctil. Luego verás cuántos datos se generan para interacciones simples.

Kotlin

private const val DEBUG_TAG = "Gestures"

class MainActivity :
        Activity(),
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener {

    private lateinit var mDetector: GestureDetectorCompat

    // Called when the activity is first created.
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = GestureDetectorCompat(this, this)
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (mDetector.onTouchEvent(event)) {
            true
        } else {
            super.onTouchEvent(event)
        }
    }

    override fun onDown(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDown: $event")
        return true
    }

    override fun onFling(
            event1: MotionEvent,
            event2: MotionEvent,
            velocityX: Float,
            velocityY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onFling: $event1 $event2")
        return true
    }

    override fun onLongPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onLongPress: $event")
    }

    override fun onScroll(
            event1: MotionEvent,
            event2: MotionEvent,
            distanceX: Float,
            distanceY: Float
    ): Boolean {
        Log.d(DEBUG_TAG, "onScroll: $event1 $event2")
        return true
    }

    override fun onShowPress(event: MotionEvent) {
        Log.d(DEBUG_TAG, "onShowPress: $event")
    }

    override fun onSingleTapUp(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapUp: $event")
        return true
    }

    override fun onDoubleTap(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTap: $event")
        return true
    }

    override fun onDoubleTapEvent(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: $event")
        return true
    }

    override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event")
        return true
    }

}

Java

public class MainActivity extends Activity implements
        GestureDetector.OnGestureListener,
        GestureDetector.OnDoubleTapListener{

    private static final String DEBUG_TAG = "Gestures";
    private GestureDetectorCompat mDetector;

    // Called when the activity is first created.
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Instantiate the gesture detector with the
        // application context and an implementation of
        // GestureDetector.OnGestureListener.
        mDetector = new GestureDetectorCompat(this,this);
        // Set the gesture detector as the double-tap
        // listener.
        mDetector.setOnDoubleTapListener(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
            return true;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent event) {
        Log.d(DEBUG_TAG,"onDown: " + event.toString());
        return true;
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2,
            float velocityX, float velocityY) {
        Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onLongPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onLongPress: " + event.toString());
    }

    @Override
    public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
            float distanceY) {
        Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString());
        return true;
    }

    @Override
    public void onShowPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onShowPress: " + event.toString());
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString());
        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
        return true;
    }
}

Cómo detectar un subconjunto de gestos compatibles

Si solo quieres procesar algunos gestos, puedes extender GestureDetector.SimpleOnGestureListener en lugar de implementar GestureDetector.OnGestureListener interfaz de usuario.

GestureDetector.SimpleOnGestureListener proporciona un implementación de todos los on<TouchEvent> métodos mostrando false para todos. Esto te permite anular solo los métodos que que te interesa. Por ejemplo, el siguiente fragmento de código crea una clase que extiende GestureDetector.SimpleOnGestureListener y anulaciones onFling() y onDown().

Ya sea que uses GestureDetector.OnGestureListener o GestureDetector.SimpleOnGestureListener, una práctica recomendada es implementa un método onDown() que muestre true. Esta es que todos los gestos comienzan con un mensaje onDown(). Si mostrar false de onDown(), como GestureDetector.SimpleOnGestureListener lo hace de forma predeterminada, el sistema supone que deseas ignorar el resto del gesto y los demás métodos de No se llama a GestureDetector.OnGestureListener. Esto podría provocar problemas inesperados en tu aplicación. Solo devolver false desde onDown() si realmente quieres ignorar un gesto completo.

Kotlin

private const val DEBUG_TAG = "Gestures"

class MainActivity : Activity() {

    private lateinit var mDetector: GestureDetectorCompat

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mDetector = GestureDetectorCompat(this, MyGestureListener())
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        mDetector.onTouchEvent(event)
        return super.onTouchEvent(event)
    }

    private class MyGestureListener : GestureDetector.SimpleOnGestureListener() {

        override fun onDown(event: MotionEvent): Boolean {
            Log.d(DEBUG_TAG, "onDown: $event")
            return true
        }

        override fun onFling(
                event1: MotionEvent,
                event2: MotionEvent,
                velocityX: Float,
                velocityY: Float
        ): Boolean {
            Log.d(DEBUG_TAG, "onFling: $event1 $event2")
            return true
        }
    }
}

Java

public class MainActivity extends Activity {

    private GestureDetectorCompat mDetector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDetector = new GestureDetectorCompat(this, new MyGestureListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if (this.mDetector.onTouchEvent(event)) {
              return true;
        }
        return super.onTouchEvent(event);
    }

    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        private static final String DEBUG_TAG = "Gestures";

        @Override
        public boolean onDown(MotionEvent event) {
            Log.d(DEBUG_TAG,"onDown: " + event.toString());
            return true;
        }

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2,
                float velocityX, float velocityY) {
            Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString());
            return true;
        }
    }
}

Recursos adicionales