Θέλω να ενεργοποιήσω την ανίχνευση χειρονομιών "fling" στην εφαρμογή Android.
Αυτό που έχω είναι ένα GridLayout
που περιέχει 9 ImageView
. Η πηγή μπορεί να βρεθεί εδώ: [Romain Guys's Grid Layout][4].
Αυτό το αρχείο που παίρνω είναι από το Photostream application του Romain Guy's και έχει προσαρμοστεί μόνο ελαφρώς.
Για την απλή κατάσταση κλικ χρειάζεται μόνο να ορίσω το onClickListener
για κάθε ImageView
που προσθέτω να είναι η κύρια activity
που υλοποιεί το View.OnClickListener
. Φαίνεται απείρως πιο περίπλοκο να υλοποιήσω κάτι που αναγνωρίζει ένα fling
. Υποθέτω ότι αυτό οφείλεται στο γεγονός ότι μπορεί να εκτείνεται σε Views
;
Αν η δραστηριότητά μου υλοποιεί
OnGestureListener
δεν ξέρω πώς να υλοποιήσω
να το ορίσω ως ακροατή χειρονομιών για
για τις προβολές Grid
ή Image
που έχω
προσθέσω.
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnGestureListener { ...
Αν η δραστηριότητά μου υλοποιεί
OnTouchListener
τότε δεν έχω καμία
onFling
μέθοδο για να την επαναλάβω
(έχει
δύο γεγονότα ως παραμέτρους που μου επιτρέπουν
να προσδιορίσω αν το fling ήταν
αξιοσημείωτο).
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnTouchListener { ...
Αν φτιάξω ένα προσαρμοσμένο View
, όπως το GestureImageView
που επεκτείνει το ImageView
δεν ξέρω πώς να πω στο activity ότι έχει συμβεί ένα fling
από το view. Σε κάθε περίπτωση, το δοκίμασα αυτό και οι μέθοδοι δεν κλήθηκαν όταν άγγιξα την οθόνη.
Πραγματικά χρειάζομαι μόνο ένα συγκεκριμένο παράδειγμα ότι αυτό λειτουργεί σε όλες τις προβολές. Τι, πότε και πώς πρέπει να επισυνάψω αυτόν τον listener
; Πρέπει να είμαι σε θέση να ανιχνεύω και μεμονωμένα κλικ.
// 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;
}
}
});
Είναι δυνατόν να τοποθετήσω μια διαφανή προβολή πάνω από την οθόνη μου για να καταγράψω τα flings;
Αν επιλέξω να μην φουσκώνω
τις παιδικές μου προβολές εικόνας από XML μπορώ να περάσω το GestureDetector
ως παράμετρο κατασκευαστή σε μια νέα υποκλάση του ImageView
που θα δημιουργήσω;
Αυτή είναι η πολύ απλή δραστηριότητα για την οποία προσπαθώ να πετύχω την ανίχνευση fling
: SelectFilterActivity (Adapted from photostream).
Έχω κοιτάξει αυτές τις πηγές: I've looking at these sources:
Τίποτα δεν έχει δουλέψει για μένα μέχρι στιγμής και ήλπιζα σε κάποιες υποδείξεις.
Ευχαριστώ τον Code Shogun, του οποίου τον κώδικα προσάρμοσα στην περίπτωσή μου.
Αφήστε τη δραστηριότητά σας να υλοποιήσει το "OnClickListener" ως συνήθως:
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;
}
}
}
Συνδέστε τον ακροατή χειρονομιών σας σε όλες τις προβολές που προσθέτετε στην κύρια διάταξη,
// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this);
imageView.setOnTouchListener(gestureListener);
Παρακολουθήστε με δέος τις μεθόδους που έχετε παρακάμψει να χτυπούν, τόσο την onClick(View v)
της δραστηριότητας όσο και την onFling
του ακροατή χειρονομιών.
public void onClick(View v) {
Filter f = (Filter) v.getTag();
FilterFullscreenActivity.show(this, input, f);
}
Ο χορός μετά το 'fling' είναι προαιρετικός αλλά ενθαρρύνεται.
Ο παραπάνω κώδικας ανίχνευσης χειρονομιών swipe είναι πολύ χρήσιμος! Ωστόσο, μπορείτε να θέλετε να κάνετε αυτή τη λύση ανεξάρτητη από την πυκνότητα, χρησιμοποιώντας τις ακόλουθες σχετικές τιμές (REL_SWIPE)
αντί για τις απόλυτες τιμές (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);
Επίσης, ως μια μικρή βελτίωση.
Ο κύριος λόγος για το μπλοκ try/catch είναι ότι το e1 θα μπορούσε να είναι null για την αρχική κίνηση.Εκτός από το try/catch, συμπεριλάβετε έναν έλεγχο για null και return. παρόμοιο με το ακόλουθο
if (e1 == null || e2 == null) return false;
try {
...
} catch (Exception e) {}
return false;