Je veux faire fonctionner la détection des gestes fling
dans mon application Android.
Ce que j'ai est une GridLayout
qui contient 9 ImageView
s. La source peut être trouvée ici : [Romain Guys's Grid Layout][4].
Le fichier que j'ai pris provient de [l'application Photostream][5] de Romain Guy et n'a été que légèrement adapté.
Dans le cas d'un simple clic, je n'ai qu'à définir le onClickListener
pour chaque ImageView
que j'ajoute pour être l'activité
principale qui implémente View.OnClickListener
. Il semble infiniment plus compliqué d'implémenter quelque chose qui reconnaît un fling
. Je suppose que c'est parce qu'il peut s'étendre sur plusieurs vues
?
Si mon activité implémente
l'implémentation de OnGestureListener
je ne sais pas comment
l'utiliser comme écouteur de gestes pour
pour les vues Grid
ou Image
que j'ajoute.
ajouter.
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnGestureListener { ...
Si mon activité implémente
OnTouchListener
alors je n'ai pas de méthode
Je n'ai pas de méthode onFling
à surcharger
(elle a
deux événements comme paramètres me permettant de
de déterminer si le coup de feu était
digne d'intérêt).
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnTouchListener { ...
Si je crée une View
personnalisée, comme GestureImageView
qui étend ImageView
, je ne sais pas comment dire à l'activité qu'un fling
s'est produit depuis la vue. En tout cas, j'ai essayé et les méthodes n'ont pas été appelées lorsque j'ai touché l'écran.
J'ai vraiment besoin d'un exemple concret de ce fonctionnement entre les vues. Comment, quand et comment dois-je attacher cet "écouteur" ? Je dois également être en mesure de détecter les clics uniques.
// 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 pour capturer les clics ?
Si je choisis de ne pas "gonfler" mes vues d'image enfant à partir de XML, puis-je passer le "GestureDetector" comme paramètre de construction à une nouvelle sous-classe de "ImageView" que je crée ?
Voici l’activité très simple pour laquelle j’essaie d’obtenir la détection de l’affichage : [SelectFilterActivity (Adapté de photostream)][6].
J'ai consulté les sources suivantes :
[Detect Gestures - Tutorial][1] (en anglais)
[Docs SDK] [2]
[Code de la calculatrice] [3]
Rien n'a fonctionné pour moi jusqu'à présent et j'espérais avoir quelques indications.
[1] : http://www.anddev.org/gesturedetector_and_gesturedetectorongesturelistener-t3204.html [2] : http://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener.html [3] : http://www.google.co.in/codesearch/p?hl=en#RzGvLIykRFs/src/com/android/calculator2/PanelSwitcher.java&q=android%20package:git://android.git.kernel.org%20Calculator2 [4] : https://github.com/selmanon/apps-for-android/blob/master/Photostream/src/com/google/android/photostream/GridLayout.java [5] : http://code.google.com/p/apps-for-android/ [6] : http://code.google.com/p/miffed/source/browse/GUI/src/uk/ac/ic/doc/gea05/miffed/gui/SelectFilterActivity.java?r=210
Merci à [Code Shogun][1], dont j'ai adapté le code à ma situation.
Laissez votre activité implémenter le "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;
}
}
}
Attachez votre écouteur de geste à toutes les vues que vous ajoutez à la disposition principale ;
// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this);
imageView.setOnTouchListener(gestureListener);
Regardez avec émerveillement vos méthodes surchargées être utilisées, à la fois le onClick(View v)
de l'activité et le onFling
de l'écouteur de gestes.
public void onClick(View v) {
Filter f = (Filter) v.getTag();
FilterFullscreenActivity.show(this, input, f);
}
La danse post "fling" est facultative mais encouragée.
[1] : http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/ [2] : http://code.google.com/p/miffed/source/browse/?r=212
Le code du détecteur de gestes de balayage ci-dessus est très utile ! Vous pouvez cependant souhaiter rendre cette solution agnostique à la densité en utilisant les valeurs relatives suivantes (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);
Également comme une amélioration mineure.
La raison principale du bloc try/catch est que e1 pourrait être nul pour le mouvement initial. En plus du try/catch, incluez un test pour null et le retour. similaire à ce qui suit
if (e1 == null || e2 == null) return false;
try {
...
} catch (Exception e) {}
return false;