Cómo detectar la dirección del deslizamiento entre izquierda / derecha y arriba / abajo

Mi pregunta: ¿Cómo puedo detectar cuándo un usuario mueve su dedo hacia arriba / abajo, hacia la izquierda / derecha (y cómo sé qué dirección de esos grupos movió su dedo)?

Mi situación: Quiero cambiar el brillo de mi aplicación cuando mueven su dedo hacia arriba y hacia abajo (arriba = más claro, abajo = más oscuro), y quiero cambiar entre actividades y / o vistas en función de su deslizamiento hacia la izquierda / derecha.

Simplemente tiene que extender la clase SimpleOnGestureListener,

Declara esto en tu clase,

private static final int SWIPE_MIN_DISTANCE = 120; private static final int SWIPE_MAX_OFF_PATH = 250; private static final int SWIPE_THRESHOLD_VELOCITY = 200; 

Como ejemplo de deslizamiento horizontal, puede ver el siguiente código,

  class MyGestureDetector extends SimpleOnGestureListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { try { if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH){ return false; } // right to left swipe if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { onLeftSwipe(); } // left to right swipe else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { onRightSwipe(); } } catch (Exception e) { } return false; } } 

Puede hacer esto de manera similar para el propósito de desplazamiento vertical.

Escribí una clase simple para esto: está bien documentado, así que no lo explicaré aquí

 public class OnSwipeListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // Grab two events located on the plane at e1=(x1, y1) and e2=(x2, y2) // Let e1 be the initial event // e2 can be located at 4 different positions, consider the following diagram // (Assume that lines are separated by 90 degrees.) // // // \ A / // \ / // D e1 B // / \ // / C \ // // So if (x2,y2) falls in region: // A => it's an UP swipe // B => it's a RIGHT swipe // C => it's a DOWN swipe // D => it's a LEFT swipe // float x1 = e1.getX(); float y1 = e1.getY(); float x2 = e2.getX(); float y2 = e2.getY(); Direction direction = getDirection(x1,y1,x2,y2); return onSwipe(direction); } /** Override this method. The Direction enum will tell you how the user swiped. */ public boolean onSwipe(Direction direction){ return false; } /** * Given two points in the plane p1=(x1, x2) and p2=(y1, y1), this method * returns the direction that an arrow pointing from p1 to p2 would have. * @param x1 the x position of the first point * @param y1 the y position of the first point * @param x2 the x position of the second point * @param y2 the y position of the second point * @return the direction */ public Direction getDirection(float x1, float y1, float x2, float y2){ double angle = getAngle(x1, y1, x2, y2); return Direction.get(angle); } /** * * Finds the angle between two points in the plane (x1,y1) and (x2, y2) * The angle is measured with 0/360 being the X-axis to the right, angles * increase counter clockwise. * * @param x1 the x position of the first point * @param y1 the y position of the first point * @param x2 the x position of the second point * @param y2 the y position of the second point * @return the angle between two points */ public double getAngle(float x1, float y1, float x2, float y2) { double rad = Math.atan2(y1-y2,x2-x1) + Math.PI; return (rad*180/Math.PI + 180)%360; } public enum Direction{ up, down, left, right; /** * Returns a direction given an angle. * Directions are defined as follows: * * Up: [45, 135] * Right: [0,45] and [315, 360] * Down: [225, 315] * Left: [135, 225] * * @param angle an angle from 0 to 360 - e * @return the direction of an angle */ public static Direction get(double angle){ if(inRange(angle, 45, 135)){ return Direction.up; } else if(inRange(angle, 0,45) || inRange(angle, 315, 360)){ return Direction.right; } else if(inRange(angle, 225, 315)){ return Direction.down; } else{ return Direction.left; } } /** * @param angle an angle * @param init the initial bound * @param end the final bound * @return returns true if the given angle is in the interval [init, end). */ private static boolean inRange(double angle, float init, float end){ return (angle >= init) && (angle < end); } } } 

Para usar simplemente extienda OnSwipeListener y anule el método onSwipe

La respuesta de Fernandour es perfecta, estoy escribiendo esta respuesta sobre cómo usarla con Activity y Fragment como muchas personas lo están buscando.

 public class MyActivity extends Activity implements View.OnTouchListener{ private RelativeLayout someLayout; //take any layout on which you want your gesture listener; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); gestureDetector=new GestureDetector(this,new OnSwipeListener(){ @Override public boolean onSwipe(Direction direction) { if (direction==Direction.up){ //do your stuff Log.d(TAG, "onSwipe: up"); } if (direction==Direction.down){ //do your stuff Log.d(TAG, "onSwipe: down"); } return true; } }); someLayout.setOnTouchListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "onTouch: "); gestureDetector.onTouchEvent(event); return true; } } 

Dando un ejemplo de uso para la respuesta de fernandohur arriba:

Si desea aplicar OnSwipeListener a una de sus vistas, entonces:
Donde sea que esté esta vista, configure un oyente táctil para esa vista, como este:

 myview.setOnTouchListener(this); 

Ahora en OnCreate de tu actividad o en tu constructor de vista personalizado haz esto:

 // Global private GestureDetectorCompat detector; // In OnCreate or custome view constructor (which extends one of Android views) detector = new GestureDetectorCompat(context, onSwipeListener); 

Reemplazar en la misma clase el evento onTouch, así:

 @Override public boolean onTouch(View view, MotionEvent motionEvent) { return detector.onTouchEvent(motionEvent); } 

Y también tienen en la misma clase este objeto oyente:

 OnSwipeListener onSwipeListener = new OnSwipeListener() { @Override public boolean onSwipe(Direction direction) { // Possible implementation if(direction == Direction.left|| direction == Direction.right) { // Do something COOL like animation or whatever you want // Refer to your view if needed using a global reference return true; } else if(direction == Direction.up|| direction == Direction.down) { // Do something COOL like animation or whatever you want // Refer to your view if needed using a global reference return true; } return super.onSwipe(direction); } 

};

Lo solucioné de esta manera:

 viewPager.setOnTouchListener(new View.OnTouchListener() { float prevX = -1; @Override public boolean onTouch(View v, MotionEvent event) { if (prevX != -1) { if (event.getX() > prevX) { if (viewPager.getCurrentItem() == 0) { // Left to Right swipe } //Log.d("DEBUG", MotionEvent.ACTION_MOVE + ":" + event.getAction() + ":" + event.getActionMasked() + ":Left Swipe" + ":" + prevX + ":" + event.getX() + ":" + viewPager.getCurrentItem()); } else if (prevX > event.getX()) { // Right to left swipe //Log.d("DEBUG", MotionEvent.ACTION_MOVE + ":" + event.getAction() + ":" + event.getActionMasked() + ":Right Swipe" + ":" + prevX + ":" + event.getX() + ":" + viewPager.getCurrentItem()); } } if (event.getAction() == MotionEvent.ACTION_MOVE) { prevX = event.getX(); } else { prevX = -1; } return false; } }); 

Las respuestas disponibles son demasiado complejas para un problema tan simple. Sugiero otro enfoque (el código es as3, pero puedes entender la idea):

 var touchDistance:Number = Point.distance(_moveTouchPoint, _startTouchPoint); if (touchDistance >= SWIPE_MIN_DISTANCE) { var xDiff:Number = _moveTouchPoint.x - _startTouchPoint.x; var yDiff:Number = _moveTouchPoint.y - _startTouchPoint.y; var yGreater:Boolean = Math.abs(yDiff) >= Math.abs(xDiff); if (yGreater) { // direction is up or down changePlayerDirectionTo(yDiff < 0 ? DIRECTION_UP : DIRECTION_DOWN); } else { // direction is left or right changePlayerDirectionTo(xDiff < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT) } } 

En cada caso, x o y será mayor en valor absoluto, que puede resolverse en un determinado conjunto de direcciones. A partir de ese momento, puede confiar en el signo de coordenadas para detectar exactamente en qué dirección.

Puede anular SimpleGestureListener y calcular la diferencia entre las coordenadas actuales del final de inicio:

 private class GestureListener extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (e2.getY() > e1.getY()) { // direction up }else { // direction down } if (e2.getX() > e1.getX()) { // direction right }else { // direction left } return true; } } 

Tengo una biblioteca de gestos de código abierto en bitbucket que hace esto. Dentro de esta biblioteca hay una clase ‘HGFling’. Esto demuestra cómo detectar la dirección de una aventura. Puede descargar la biblioteca desde: https://bitbucket.org/warwick/hacergestov3 . Es de código abierto.