2013-06-06 16 views
11

Update: Siehe Bounty für erweiterte Frage.Gestenzuhörer onFling nicht aktiv

Ich habe eine GestureDetector Setup auf einem ListView. Das ListView ist ein ganzes Fragment, das von der Seite des Fensters kommt und teilweise ein anderes Fragment überlagert. Ich möchte dem Benutzer die Möglichkeit geben, es zu schließen (d. H. Wunderlist ist ein großartiges Beispiel für diese Funktion auf der rechten Seite).

Hier ist mein Setup:

gestureListener = new View.OnTouchListener() { 
     public boolean onTouch(View v, MotionEvent event) { 

      if (gestureDetector.onTouchEvent(event)) { 
       return true; 
      } 

      return false; 
     } 
    }; 
    listView.setOnTouchListener(gestureListener); 

Der Zuhörer selbst:

public class GestureListener extends SimpleOnGestureListener { 

     private static final int SWIPE_MIN_DISTANCE = 180; 
     private static final int SWIPE_THRESHOLD_VELOCITY = 50; 

     @Override 
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
       float velocityY) { 

      try { 
       if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE 
         && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { 

        FragmentManager fma = getActivity() 
          .getSupportFragmentManager(); 



        FragmentManager fm = getFragmentManager(); 
        FragmentTransaction t = fm.beginTransaction(); 

        SherlockListFragment mFrag = new RateReviewFragment(); 

        t.add(R.id.main_frag, mFrag); 
        t.setCustomAnimations(R.anim.animation_enter, 
          R.anim.animation_leave); 
        t.remove(mFrag); 
        t.commit(); 

       } 
       return false; 
      } catch (Exception e) { 

      } 
      return false; 
     } 





     @Override 
     public void onLongPress(MotionEvent e) { 

      // edited out; this opens up a context menu 
     } 

    } 

Manchmal, wenn die ListView scrollt nach unten (oder Liste Scrollen mit Klicks auf einer Listenzeile unterbrochen) hört die GestureListener einfach auf ... zuhören. Swiping wird nicht funktionieren. Sie müssen nach oben scrollen, um es wieder zum Laufen zu bringen.

Wenn mir jemand helfen kann, diese Probleme zu isolieren, wäre ich dankbar!

UPDATE: Nur eine Frage bleibt, "der Zuhörer hält hören"

UPDATE TWO: Ich habe heraus kann dachte, was ist der Grund dafür; Ich weiß nicht, die Lösung:

Ich habe etwas nach dem Protokollieren meiner Aktionen gefunden; Je niedriger ich in der Liste bin (und je mehr ich damit interagiere), die Messungen sind nicht konsistent. Zum Beispiel, wenn ich meinen Finger einen Zentimeter nach links und rechts bewege - ganz oben in der Liste, wird es sagen, dass ich zum Beispiel 200 Pixel bewegt habe. Aber wenn ich das oben genannte Problem habe, ist es viel niedriger, vielleicht 50, für die 1 Zentimeter Entfernung. Das Fenster schließt also nicht, weil es meine if Bedingungen nicht erfüllt.

Sidenote: Ich habe mehr als einmal gesagt, das Problem ist, wenn "mit der Liste interagieren". Das heißt: Wenn ich schnell von oben nach unten blättern kann; kein Problem; Aber wenn ich mich langsam nach unten arbeite, vielleicht auf den Bildschirm tippe, ein- und ausbleiche, auf die Knöpfe auf der listView klicke, von denen einige eine neue Aktivität öffnen (und dann zur selben Position zurückkehren), ist das "interagierend" mit " .

+0

Wenn Sie für die neue gmail App Art Schublade suchen von der linken Seite möchten Sie vielleicht einen Blick darauf werfen - http://developer.android.com/training/implementing-navigation/nav-drawer.html – Varun

+0

@Varun das ist nicht diese Art von Slider für die Navigation. Ich habe das eigentlich schon auf der linken Seite. Das ist eine rechte Seite, um Inhalte zu zeigen. – KickingLettuce

Antwort

3

dies versuchen,

gestureDetector = new GestureDetector(getActivity(), 
      new GestureListener()); 
    View.OnTouchListener gestureListener = new View.OnTouchListener() { 
     public boolean onTouch(View v, MotionEvent event) { 
      listView.onTouchEvent(event); 
      gestureDetector.onTouchEvent(event); 

      return true; 
     } 
    }; 
    listView.setOnTouchListener(gestureListener); 

und die folgende Änderung

@Override 
public boolean onScroll(MotionEvent e1, MotionEvent e2, 
       float distanceX, float distanceY) { 
    return true; 
} 

EDIT: Ich sah die App Wunderlist, wenn u die Funktionalität ausprobieren, diesen Ansatz simulieren wollen ,

Verwenden Sie onInterceptTouch für das Stammlayout (von dem listView ein ch ist ild von), innerhalb dieser Methode u müssen prüfen whteher der Benutzer oder nicht, wie die folgenden geklaut hat,

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
    if (ev.getAction() == MotionEvent.ACTION_MOVE) { 
    if(/* Check your condition here */) { 
     // User has swiped 
     return true; 
    } 
    } 

    return false; // return false so that the event will be passed to child views. 
} 

für weitere Informationen Android onInterceptTouchEvent

+0

hey danke für den Vorschlag; Leider verliere ich immer noch gelegentlich die Fähigkeit, das Fenster zu schließen. – KickingLettuce

+0

Nach meiner Erfahrung mit Android können Sie nicht erwarten, dass das Gerät immer die richtigen Berührungspunkte für die Benutzerinteraktion bietet ("erwartet" wäre ein besseres Wort). Es liegt an uns (den Entwicklern), einen solchen Fall zu behandeln. Warum also nicht die Bedingungen von onFling() durchspielen, um die beste zu wählen, bei der 8/10 mal funktionieren würde. Hoffe es hilft – 66CLSjY

+0

Ich stimme zu. Wenn Sie meine aktualisierte Frage sehen, habe ich eine große Inkonsistenz gefunden. Obwohl ich weiß, dass es einen Weg gibt, dies zu tun, wie Wunderlist es perfekt ausführt. – KickingLettuce

2

Änderung der OnTouch auf diese Weise:

@Override 
public boolean onTouch(View arg0, MotionEvent arg1) { 
    boolean consumed = gestureDetector.onTouchEvent(event); 
    if (event.getAction() == MotionEvent.ACTION_MOVE) { 
       return false; 
    } 

    return consumed; 
} 
+0

Danke. Will test ... Frage: Ich hätte nicht gedacht, dass onTouch Teil dieser SimpleOnGesture Methode ist? – KickingLettuce

+0

noch der Gestendetektor leitet Touch-Ereignisse an es – Blackbelt

+0

scheint dies entgegengesetzte Wirkung zu haben. Es tötet die gesamte Swipe-to-Close-Fähigkeit; Dennoch bleiben alle drei oben genannten Probleme ein Problem. – KickingLettuce

1

nicht wirklich tun sicher, ob dies helfen wird, als Gott weiß, was hinter den Kulissen vor sich geht mit all diesen Fragen Fragmente aber versuchen Sie dies:

Nach onTouch wurde aufgerufen, vor der Rückgabe falscher Prüfung, ob GestenDetector noch am Leben ist (nicht null), (durch Senden von Rückruf oder etwas an die ListView-Klasse), wenn nicht neue Instanz davon erstellen und erneut aufrufen

+0

Nun, ich 'Log.d'' GestenListener', und ich glaube nicht, dass es jemals null war. Ich habe mein 'listView' in Position gebracht, wo mein' onFling' nicht funktionieren würde, und der Listener Logging noch etwas ... wenn es null war, schien es das Log würde dies zeigen? – KickingLettuce

+0

versuchen, Breakpoint und sehen, ob die Instanz null ist? –

+0

Ich habe mein Bestes versucht, das Debugging-System "langsam als Schmutz" zu benutzen und es war schwierig zu sagen, ob es null war ... Ich habe "Log.d" gelesen, um zu sehen, wann "Ereignis" und "OnFling" aufgerufen wurden. Einige Male wurden sie beide gerufen, auch wenn ich wischte und das 'Fragment' reagierte nicht auf den Fling. Das deutet fast darauf hin, dass mein Fling-Code falsch ist? Aber ich glaube alle Swipes erfüllt die Kriterien in Länge und Geschwindigkeit. – KickingLettuce

0

Firtly versuchen OnTouchListener so zu machen:

View.OnTouchListener gestureListener = new View.OnTouchListener() { 
    public boolean onTouch(View v, MotionEvent event) { 
    gestureDetector.onTouchEvent(event); 
     return true; 
    } 
}; 

Dann - Sie sind immer wieder false in onFling(). Zurückgeben true in try/catch Klausel. Und versuchen Sie, die gleichen Daten an die onScroll Methode in Else-Klausel innerhalb onFling zu übergeben.

+0

Ich hatte immer etwas Verwirrung darüber; Was macht die Rückkehr von "falsch" im Gegensatz zu "wahr"? Das Ändern von FIRST 'false' in' onFling() '(in' true') betrifft im Wesentlichen den normalen 'listView'-Bildlauf. Es wird Ihnen erlauben, durch die Liste zu scrollen, aber es wird sich nur bewegen, wenn Ihr Finger berührt ... – KickingLettuce

+0

Sie müssen in onFling den horizontalen Fling erkennen und die Liste selbst scrollen, denke ich. Über true/false: Während ich wie Dokumentation vorging sagt mein GestenListener nicht (ich habe es bisher nicht geschrieben). Ich habe dir nur geraten, das zu tun, was ich getan habe. – Lingviston

1

Erste

Ich nehme zur Kenntnis, dass Sie in Ihrer Geste Zuhörer true in onDown zurückzukehren. Wenn ich Ihre Frage richtig verstanden habe, hinterlassen Sie Tipp- und vertikale Swipe-Ereignisse für die ListView, und Sie sind nur an horizontalen Swipe-Ereignissen in Ihrem Code interessiert.

Warum nicht alle Funktionen entfernen, an denen Sie nicht interessiert sind, und damit alles, was Sie nicht interessiert, an die ListView? Wenn Sie sie haben müssen, geben Sie mindestens false zurück, was die Standardeinstellung ist (siehe here).

Als beiseite, das code für AbsListView (die Eltern von ListView) zeigt ein ziemlich komplexes Zustandssystem für Armaturen und klaut Handhabung, so ist es wahrscheinlich so untocuhed wie möglich am besten links in meiner Ansicht

Zweitens

In Anbetracht Ihrer neueren Beobachtungen besteht der Schlüssel vielleicht darin, das Verhältnis zwischen X- und Y-Verschiebung und nicht die absolute Größe des Wischens zu berücksichtigen.Während ich nicht die Änderung der gemeldeten Größe Swipe erklären kann, was sind wir wirklich daran interessiert ist, eine Bewegung, die überwiegend horizontal ist, das heißt:

(change in X) >> (change in Y) 

dies erreicht werden kann, wie folgt:

if ((velocityY == 0.0f) || (Math.abs(velocityX/velocityY) > 3.0f) { 
    // The movement is predominantly horizontal 
    // Put other checks here (like direction and so on) 
    // Then do the stuff 
} 
Diese

hat den Vorteil, nicht mit e1 oder e2, die uns bringt auf ...

Drittens

Wie Sie bemerken, ist das Problem, wenn Sie mit der ListView interagiert haben. An diesem Punkt können mehrere Zeiger in der Event gemeldet werden. Es ist nicht garantiert, dass die von ihnen zurückgegebenen X- und Y-Standardinformationen sich auf ein bestimmtes Zeigerereignis beziehen. Es ist wahrscheinlich wert, dass Sie Informationen aus dem gleichen Zeiger Ereignisse vergleichen, wenn Sie Berechnungen zu tun, die X und Y wollen, mit so etwas wie:

int numPointers = e1.getPointerCount(); 
for (int pointerIndex1 = 0; pointerIndex1 < numPointers; pointerIndex1++) { 
    int pointerId = e1.getPointerId(pointerIndex1); 
    // find index for pointerId in e2. 

    float deltaX = e2.getX(pointerIndex2) - e1.getX(pointerIndex1); 
    // and so on 
} 
+0

Ich habe etwas herausgefunden, nachdem ich meine Aktionen protokolliert habe; Je niedriger ich in der Liste bin (und je mehr ich damit interagiere), die Messungen sind nicht konsistent. Zum Beispiel, wenn ich meinen Finger einen Zentimeter nach links und rechts bewege - ganz oben in der Liste, wird es sagen, dass ich zum Beispiel 200 Pixel bewegt habe. Aber wenn ich das Problem oben habe, ist es viel niedriger, vielleicht 50, für die SAME 1 Zentimeter Entfernung. Das Fenster wird also nicht geschlossen, weil es meine Bedingungen für "Wenn" nicht erfüllt. – KickingLettuce

+0

Hey ich schätze das Feedback wieder. Ich werde sehen, was ich herausgefunden habe und Sie auf dem Laufenden halten. – KickingLettuce

Verwandte Themen