Ich möchte die Gestenerkennung "fling" in meiner Android-Anwendung zum Laufen bringen.
Was ich habe ist ein GridLayout
, das 9 ImageView
s enthält. Die Quelle kann hier gefunden werden: [Romain Guys's Grid Layout][4].
Diese Datei stammt aus Romain Guys Photostream application und wurde nur leicht angepasst.
Für die einfache Klick-Situation muss ich nur den onClickListener
für jede ImageView
, die ich hinzufüge, zur Haupt-"Aktivität" machen, die den View.OnClickListener
implementiert. Es scheint unendlich viel komplizierter zu sein, etwas zu implementieren, das einen Fling
erkennt. Ich nehme an, das liegt daran, dass es sich über Views
erstrecken kann?
Wenn meine Aktivität Folgendes implementiert
OnGestureListener" implementiert, weiß ich nicht, wie ich
das als Gesten-Listener für das
die Grid
oder die Image
Ansichten, die ich
hinzufügen.
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnGestureListener { ...
Wenn meine Aktivität implementiert OnTouchListener` implementiert, habe ich keine OnFling"-Methode zu überschreiben (sie hat zwei Ereignisse als Parameter, die es mir erlauben zu bestimmen, ob der Wurf nennenswert war).
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnTouchListener { ...
Wenn ich eine benutzerdefinierte View
mache, wie GestureImageView
, die ImageView
erweitert, weiß ich nicht, wie ich der Activity mitteilen kann, dass ein Fling
von der View aufgetreten ist. Auf jeden Fall habe ich das versucht und die Methoden wurden nicht aufgerufen, wenn ich den Bildschirm berührte.
Ich brauche wirklich nur ein konkretes Beispiel dafür, wie dies über verschiedene Ansichten hinweg funktioniert. Was, wann und wie sollte ich diesen "Listener" anhängen? Ich muss auch in der Lage sein, einzelne Klicks zu erkennen.
// 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;
}
}
});
Ist es möglich, eine transparente Ansicht über den oberen Teil meines Bildschirms zu legen, um Bewegungen zu erfassen?
Wenn ich meine untergeordneten Bildansichten nicht aus XML aufblasen möchte, kann ich dann den "GestureDetector" als Konstruktorparameter an eine neue Unterklasse von "ImageView" übergeben, die ich erstelle?
Dies ist die sehr einfache Aktivität, für die ich versuche, die "fling"-Erkennung zum Laufen zu bringen: SelectFilterActivity (Adapted from photostream).
Ich habe mir diese Quellen angesehen:
Bis jetzt hat bei mir nichts funktioniert und ich hoffte auf ein paar Hinweise.
Vielen Dank an Code Shogun, dessen Code ich an meine Situation angepasst habe.
Lassen Sie Ihre Aktivität OnClickListener
wie gewohnt implementieren:
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;
}
}
}
Hängen Sie Ihren Gesten-Listener an alle Ansichten an, die Sie dem Hauptlayout hinzufügen;
// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this);
imageView.setOnTouchListener(gestureListener);
Beobachten Sie staunend, wie Ihre überschriebenen Methoden aufgerufen werden, sowohl die onClick(View v)
der Aktivität als auch die onFling
des Gestenhörers.
public void onClick(View v) {
Filter f = (Filter) v.getTag();
FilterFullscreenActivity.show(this, input, f);
}
Der Tanz nach dem "Fling" ist optional, aber erwünscht.
Der obige Code zur Erkennung von Wischgesten ist sehr nützlich! Sie können diese Lösung jedoch dichteunabhängig machen, indem Sie die folgenden relativen Werte (REL_SWIPE)
anstelle der absoluten Werte (SWIPE_)
verwenden
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);
Auch als eine kleine Verbesserung.
Der Hauptgrund für den try/catch-Block ist, dass e1 bei der ersten Bewegung null sein könnte. Fügen Sie zusätzlich zum try/catch-Block einen Test für null und return ein. ähnlich dem folgenden
if (e1 == null || e2 == null) return false;
try {
...
} catch (Exception e) {}
return false;