1162 votes

Android de base de la détection de mouvement

J'ai lutté pour obtenir de l' fling détection de mouvement de travail sur mon application Android aujourd'hui. J'ai été à la recherche à ces sources;

Rien n'a fonctionné pour moi jusqu'à présent et j'ai été en espérant pour certains pointeurs.

Ce que j'ai est un GridLayout qui contient 9 ImageViews. La source peut être trouvé ici: Romain Gars de la Grille de Mise en page.

Ce fichier est de prendre de Romain Guy Photostream application et a été légèrement adapté.

Pour la simple clic situation, j'ai besoin seulement de régler le onClickListener pour chaque ImageView - je ajouter de la principale activity qui implémente View.OnClickListener. Il semble infiniment plus compliqué à mettre en place quelque chose qui reconnaît un fling. Je présume que c'est parce qu'il peut s'étendre views?

  • Si mon activité met en œuvre OnGestureListener Je ne sais pas comment le définir comme le geste d'un écouteur pour l' Grid ou Image points de vue que je ajouter.

    public class SelectFilterActivity extends Activity implements
       View.OnClickListener, OnGestureListener { ...
    
  • Si mon activité met en œuvre OnTouchListener alors je n'ai pas onFling méthode de override (il a deux événements en tant que paramètres de me permettre pour déterminer si l'aventure a été à noter).

    public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnTouchListener { ...
    
  • Si je fais une coutume View, comme GestureImageView qui s'étend au - ImageView je ne sais pas comment le dire à l'activité que l' fling a eu lieu à partir de la vue. En tout cas, j'ai essayé et les méthodes n'étaient pas appelé quand j'ai touché l'écran.

J'ai vraiment juste besoin d'un exemple concret de ce travail à travers les points de vue. Quoi, quand et comment dois-je joindre cette listener? J'ai besoin d'être en mesure de détecter unique clics.

// Gesture detection
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        int dx = (int) (e2.getX() - e1.getX());
        // don't accept the fling if it's too short
        // as it may conflict with a button push
        if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {
            if (velocityX > 0) {
                moveRight();
            } else {
                moveLeft();
            }
            return true;
        } else {
            return false;
        }
    }
});

Est-il possible de poser une vue transparente sur le haut de mon écran à capturer jette? Si je choisis de ne pas inflate mon enfant vues d'images à partir de XML puis-je passer l' GestureDetector comme un paramètre de constructeur d'une nouvelle sous-classe d' ImageView que je créer?

C'est très simple activité que je vais essayer d'obtenir l' fling de détection de travailler pour: SelectFilterActivity (Adapté de photostream).

Tout conseil serait grandement apprécié. Toutes mes excuses si la question est disjoint, veuillez demander des explications, et j'ai ferons un plaisir de vous raconter les détails de ce que j'ai essayé.

840voto

gav Points 11479

Merci pour le Code Shogun, dont le code que j'ai adapté à ma situation.

Laissez votre activité mettre en œuvre OnClickListener comme d'habitude:

public class SelectFilterActivity extends Activity implements OnClickListener
{

    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;
    private GestureDetector gestureDetector;
    View.OnTouchListener gestureListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /* ... */

        // Gesture detection
        gestureDetector = new GestureDetector(this, new MyGestureDetector());
        gestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return gestureDetector.onTouchEvent(event);
            }
        };

    }

    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) {
                    Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                // nothing
            }
            return false;
        }

            @Override
        public boolean onDown(MotionEvent e) {
              return true;
        }
    }
}

Fixez votre geste auditeur à tous les points de vue que vous ajoutez à la page principale;

// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this); 
imageView.setOnTouchListener(gestureListener);

Regardez dans la crainte que vos méthodes de remplacement sont touchés, à la fois le onClick(View v) de l'activité et de la onFling du geste de l'auditeur.

public void onClick(View v) {
        Filter f = (Filter) v.getTag();
        FilterFullscreenActivity.show(this, input, f);
}

Le poster "fling' la danse est facultatif, mais recommandé.

Espérons que cela aide quelqu'un d'autre!

Vab

215voto

Xion Points 11130

L'une des réponses ci-dessus mentionne le traitement des différents densité de pixels, mais suggère le calcul du passage de paramètres à la main. Il est intéressant de noter que vous pouvez réellement obtenir la mise à l'échelle, des valeurs raisonnables du système à l'aide d' ViewConfiguration classe:

final ViewConfiguration vc = ViewConfiguration.get(getContext());
final int swipeMinDistance = vc.getScaledPagingTouchSlop();
final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
final int swipeMaxOffPath = vc.getScaledTouchSlop();
// (there is also vc.getScaledMaximumFlingVelocity() one could check against)

J'ai remarqué que l'utilisation de ces valeurs causes de la "sentir" laventure, pour plus de cohérence entre l'application et dans le reste du système.

152voto

Thomas Fankhauser Points 1899

Je le fais un peu différents, et a écrit un supplément de détecteur de classe qui implémente l' View.onTouchListener

onCreateest tout simplement l'ajouter à la plus faible de mise en page comme ceci:

ActivitySwipeDetector activitySwipeDetector = new ActivitySwipeDetector(this);
lowestLayout = (RelativeLayout)this.findViewById(R.id.lowestLayout);
lowestLayout.setOnTouchListener(activitySwipeDetector);

où id.lowestLayout est l'id.xxx pour la vue la plus basse dans la mise en page de la hiérarchie et lowestLayout est déclaré comme un RelativeLayout

Et puis il y a l'activité réelle de balayage du détecteur de classe:

public class ActivitySwipeDetector implements View.OnTouchListener {

static final String logTag = "ActivitySwipeDetector";
private Activity activity;
static final int MIN_DISTANCE = 100;
private float downX, downY, upX, upY;

public ActivitySwipeDetector(Activity activity){
    this.activity = activity;
}

public void onRightToLeftSwipe(){
    Log.i(logTag, "RightToLeftSwipe!");
    activity.doSomething();
}

public void onLeftToRightSwipe(){
    Log.i(logTag, "LeftToRightSwipe!");
    activity.doSomething();
}

public void onTopToBottomSwipe(){
    Log.i(logTag, "onTopToBottomSwipe!");
    activity.doSomething();
}

public void onBottomToTopSwipe(){
    Log.i(logTag, "onBottomToTopSwipe!");
    activity.doSomething();
}

public boolean onTouch(View v, MotionEvent event) {
    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

       // swipe horizontal?
        if(Math.abs(deltaX) > Math.abs(deltaY))
        {
            if(Math.abs(deltaX) > MIN_DISTANCE){
                // left or right
                if(deltaX < 0) { this.onRightSwipe(); return true; }
                if(deltaX > 0) { this.onLeftSwipe(); return true; }
            }
            else {
                    Log.i(logTag, "Horizontal Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                    return false; // We don't consume the event
            }
        }
        // swipe vertical?
        else 
        {
            if(Math.abs(deltaY) > MIN_DISTANCE){
                // top or down
                if(deltaY < 0) { this.onDownSwipe(); return true; }
                if(deltaY > 0) { this.onUpSwipe(); return true; }
            }
            else {
                    Log.i(logTag, "Vertical Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                    return false; // We don't consume the event
            }
        }

            return true;
        }
    }
    return false;
}

}

Fonctionne très bien pour moi!

97voto

Marek Sebera Points 15987

J'ai légèrement modifié et réparé solution de Thomas Fankhauser

Tout le système se compose de deux fichiers, SwipeInterface et ActivitySwipeDetector


SwipeInterface.java

import android.view.View;

public interface SwipeInterface {

    public void bottom2top(View v);

    public void left2right(View v);

    public void right2left(View v);

    public void top2bottom(View v);

}

Détecteur de

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class ActivitySwipeDetector implements View.OnTouchListener {

    static final String logTag = "ActivitySwipeDetector";
    private SwipeInterface activity;
    static final int MIN_DISTANCE = 100;
    private float downX, downY, upX, upY;

    public ActivitySwipeDetector(SwipeInterface activity){
        this.activity = activity;
    }

    public void onRightToLeftSwipe(View v){
        Log.i(logTag, "RightToLeftSwipe!");
        activity.right2left(v);
    }

    public void onLeftToRightSwipe(View v){
        Log.i(logTag, "LeftToRightSwipe!");
        activity.left2right(v);
    }

    public void onTopToBottomSwipe(View v){
        Log.i(logTag, "onTopToBottomSwipe!");
        activity.top2bottom(v);
    }

    public void onBottomToTopSwipe(View v){
        Log.i(logTag, "onBottomToTopSwipe!");
        activity.bottom2top(v);
    }

    public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction()){
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            return true;
        }
        case MotionEvent.ACTION_UP: {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

            // swipe horizontal?
            if(Math.abs(deltaX) > MIN_DISTANCE){
                // left or right
                if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }
                if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }
            }
            else {
                Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
            }

            // swipe vertical?
            if(Math.abs(deltaY) > MIN_DISTANCE){
                // top or down
                if(deltaY < 0) { this.onTopToBottomSwipe(v); return true; }
                if(deltaY > 0) { this.onBottomToTopSwipe(v); return true; }
            }
            else {
                Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
                v.performClick();
            }
        }
        }
        return false;
    }

}

elle s'utilise comme ceci:

ActivitySwipeDetector swipe = new ActivitySwipeDetector(this);
LinearLayout swipe_layout = (LinearLayout) findViewById(R.id.swipe_layout);
swipe_layout.setOnTouchListener(swipe);

Et dans la mise en oeuvre Activity vous avez besoin pour mettre en œuvre des méthodes de SwipeInterface, et vous pouvez trouver sur quel point de Vue le Balayage de l'Événement a été appelé.

@Override
public void left2right(View v) {
    switch(v.getId()){
        case R.id.swipe_layout:
            // do your stuff here
        break;
    }       
}

68voto

paiego Points 1781

Le mouvement de balayage du détecteur de code ci-dessus est très utile! Vous pouvez néanmoins vous souhaitez faire cette densité de solution agnostique à l'aide de la suite de valeurs relatives, (REL_SWIPE) plutôt que les valeurs absolues (SWIPE_)

DisplayMetrics dm = getResources().getDisplayMetrics();

int REL_SWIPE_MIN_DISTANCE = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);
int REL_SWIPE_MAX_OFF_PATH = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);
int REL_SWIPE_THRESHOLD_VELOCITY = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X