web-dev-qa-db-fra.com

Comment détecter la direction du balayage entre gauche/droite et haut/bas

Ma question: Comment est-ce que je détecte quand un utilisateur bouge son doigt de haut en bas par rapport à gauche/à droite (et comment savoir dans quelle direction de ces groupes leur doigt s'est déplacé)?

Ma situation: Je souhaite modifier la luminosité de mon application lorsqu'ils bougent leur doigt de haut en bas (haut = plus clair, bas = plus sombre) et je souhaite basculer entre les activités et/ou les vues en fonction de leur gauche/glisser à droite.

48
kentcdodds

Vous devez simplement étendre la classe SimpleOnGestureListener,

Déclarez ceci dans votre classe,

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;

Comme exemple de balayage horizontal, vous pouvez voir le code ci-dessous,

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

Vous pouvez le faire de la même manière pour un balayage vertical.

55
Ice Box

J'ai écrit un cours simple pour cela: c'est bien documenté, donc je ne l'expliquerai pas ici

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.fromAngle(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 fromAngle(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);
        }
    }
 }

Pour utiliser simplement étendre la OnSwipeListener et substituer la méthode onSwipe

125
fernandohur

Fernandour réponse est parfaite, je vous écris cette réponse sur la façon de l’utiliser avec Activity et Fragment car beaucoup de gens le recherchent.

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


}
18
farhan patel

Donner un Exemple d'utilisation pour fernandohur answer above:

Si vous souhaitez appliquer OnSwipeListener à l'un de vos points de vue, procédez comme suit: 
Où que cette vue soit - définissez un écouteur tactile pour cette vue, comme ceci:

myview.setOnTouchListener(this);

Maintenant, dans OnCreate de votre activité ou dans votre constructeur de vue personnalisée, procédez comme suit:

// Global
private GestureDetectorCompat detector; 

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

Substituez dans la même classe l'événement onTouch, comme ceci:

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

Et aussi dans la même classe cet objet écouteur: 

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

};

9
Mercury

J'ai résolu de cette façon:

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;
        }
    });
1
rajesh

Ajout de l’implémentation Kotlin pour @Fernandour answer. Pour Java, regardez @ f arhan patel answer J'ajoute ceci parce que j’avais de la difficulté à espérer que cela sauvera du temps à quelqu'un.

class ClientFragment : Fragment(), View.OnTouchListener {

    private lateinit var gestureDetector: GestureDetector

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
        Log.d(TAG, "onTouch: ");
        gestureDetector.onTouchEvent(event);
        return true
    }


override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

 ...



 gestureDetector = GestureDetector(activity, object : OnSwipeListener() {

            override fun onSwipe(direction: Direction): Boolean {

                when(direction){
                   Direction.up ->
                   {
                       Log.d(TAG, "onSwipe: up")
                       sendCommand("UP")
                       return true
                   }
                     Direction.down ->{
                         Log.d(TAG, "onSwipe: down")
                         sendCommand("DOWN")
                         return true
                     }

                    Direction.left ->
                    {
                        Log.d(TAG, "onSwipe: left")
                        sendCommand("LEFT")
                        return true

                    }
                    Direction.right ->{
                        Log.d(TAG, "onSwipe: right")
                        sendCommand("RIGHT")
                        return true

                    }
                    else -> {
                    }
                }
                return true
            }


        })
        dpadLayout.setOnTouchListener(this)
0
Hitesh Sahu

Les réponses disponibles sont beaucoup trop complexes pour un problème aussi simple… Je suggère une autre approche (le code est as3, mais vous pouvez avoir l’idée):

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

Dans chaque cas, x ou y seront plus importants en valeur absolue, ce qui peut résoudre certaines directions. A partir de là, vous pouvez compter sur le signe des coordonnées pour détecter exactement quelle direction.

0
Martin Asenov

Vous pouvez remplacer SimpleGestureListener et calculer le diff entre les coordonnées actuelles du début à la fin:

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;
    }
}
0
box

J'ai une bibliothèque de mouvements open source sur bitbucket qui le fait. Dans cette bibliothèque se trouve une classe 'HGFling'. Cela montre comment détecter la direction d'une aventure. Vous pouvez télécharger la bibliothèque à l’adresse: https://bitbucket.org/warwick/hacergestov3 . C'est open source.

0
user2288580