2011-01-13 10 views
10

Ich habe eine Aktivität, die einen ViewFlipper enthält. Der ViewFlipper enthält 2 Layouts, bei denen es sich im Wesentlichen nur um ListViews handelt.Probleme beim Erkennen von Gesten über ListView

Also die Idee hier ist, dass ich zwei Listen habe und von einem zum anderen zu navigieren, würde ich einen horizontalen Swipe verwenden.

Ich habe das funktioniert. Wie auch immer das Element, auf das sich der Finger bezieht, wenn der Swipe beginnt, wird auch auf diesen Gegenstand geklickt.

Hier ist der relevante Code, den ich habe:

public class MyActivity extends Activity implements OnItemClickListener, 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 mGestureDetector; 
    View.OnTouchListener mGestureListener; 

    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) { 
        if (mCurrentScreen != SCREEN_SECONDLIST) { 
         mCurrentScreen = SCREEN_SECONDLIST; 
         mFlipper.setInAnimation(inFromRightAnimation()); 
         mFlipper.setOutAnimation(outToLeftAnimation()); 
         mFlipper.showNext(); 
         updateNavigationBar(); 
        } 
       } 
       else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { 
        if (mCurrentScreen != SCREEN_FIRSTLIST) { 
         mCurrentScreen = SCREEN_FIRSTLIST; 
         mFlipper.setInAnimation(inFromLeftAnimation()); 
         mFlipper.setOutAnimation(outToRightAnimation()); 
         mFlipper.showPrevious(); 
         updateNavigationBar(); 
        } 
       } 
      } catch (Exception e) { 
       // nothing 
      } 
      return true; 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if (mGestureDetector.onTouchEvent(event)) 
      return true; 
     else 
      return false; 
    } 





    ViewFlipper mFlipper; 

    private int mCurrentScreen = SCREEN_FIRSTLIST; 

    private ListView mList1; 
    private ListView mList2; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     setContentView(R.layout.layout_flipper); 

     mFlipper = (ViewFlipper) findViewById(R.id.flipper); 

     mGestureDetector = new GestureDetector(new MyGestureDetector()); 
     mGestureListener = new View.OnTouchListener() { 
      public boolean onTouch(View v, MotionEvent event) { 
       if (mGestureDetector.onTouchEvent(event)) { 
        return true; 
       } 
       return false; 
      } 
     }; 

     // set up List1 screen 

     mList1List = (ListView)findViewById(R.id.list1); 
     mList1List.setOnItemClickListener(this); 
     mList1List.setOnTouchListener(mGestureListener); 

     // set up List2 screen 
     mList2List = (ListView)findViewById(R.id.list2); 
     mList2List.setOnItemClickListener(this); 
     mList2List.setOnTouchListener(mGestureListener); 

    } 

    … 
} 

Wenn ich das ändern "return true;" Aussage vom GestureDetector zu "return false;", bekomme ich keine langen Klicks. Leider bekomme ich normale Klicks.

Weiß jemand, wie ich das umgehen kann?

Antwort

7

Nur mit einem völlig anderen Ansatz in einer völlig anderen Antwort zu werfen ...

Ich habe eine benutzerdefinierte Ansicht gemacht SwipeView genannt, es ist Open-Source-etc etc bla bla bla. Es lassen sollten Sie tun, was Sie so einfach wie gehen wollen:

mSwipeView.addChild(myList1); 
mSwipeView.addChild(myList2); 

Sie nicht zu verwirren haben etwa mit Geste Detektoren oder irgendetwas, und die die Swipe sollten Sie mit dem Finger folgen, wie Sie es tun .. .

(Das liest sich wie eine schreckliche schreckliche Werbung, bitte entschuldige mich.Es war ein langer Tag;)

haben einige wunderbare Links:

http://jasonfry.co.uk/?id=23

http://jasonfry.co.uk/?id=24

http://jasonfry.co.uk/?id=28

+0

Dies ist ähnlich einer Komponente, die ich vor kurzem entwickelt, außer dass ich Ansichtsrecycling zu mir und seine hinzugefügt unterstützt von einem listAdapter. Im Grunde habe ich eine Menge ListView-Code zusammengefügt und an eine benutzerdefinierte Gesten-gesteuerte HorizontalScrollView-Datei angehängt. – jfelectron

+0

Ja, ich arbeite daran, das auch zu SwipeView hinzuzufügen! Außerdem habe ich gerade (vor knapp 2 Minuten) bemerkt, dass es einen Fehler mit ListViews auf einem SwipeView gibt. Ich habe jetzt den Fehler behoben und das Git Repo aktualisiert. https://github.com/fry15/uk.co.jasonfry.android.tools – jsonfry

+3

jfelectron gehört Ihnen auf GIThub obwohl? –

0

[Bearbeiten] Scratch, total falsch.

Ich denke, Sie müssten diesen Teil aktualisieren und erkennen, ob Sie nach links oder rechts scrollen, und geben Sie wahr zurück, wenn Sie in einem Wisch-Zustand waren. Zumindest würde ich dort zuerst nachsehen.

mGestureListener = new View.OnTouchListener() { 
      public boolean onTouch(View v, MotionEvent event) { 
       if (mGestureDetector.onTouchEvent(event)) { 
        return true; 
       } 
       return false; 
      } 
     }; 

Fortsetzung mit meinem schlechten Beispiel, tut mir leid.

Innerhalb der onTouch glaube ich, Sie können die event.getAction() testen und feststellen, ob ein langer Klick aufgetreten ist. Wenn dies der Fall ist und Sie sich in einer schleudernden Bewegung befinden, kehren Sie zurück, um den langen Klick zu erfassen.

Angst, das ist mehr ein Vorschlag als eine endgültige Antwort.

Überprüfen Sie auch die anderen auf [Methoden], die Sie von SimpleOnGestureListener überschreiben können. Just checked und

@Override 
public void onLongPress(MotionEvent e) { 
    // TODO Auto-generated method stub 
    super.onLongPress(e); 
} 

könnte etwas sein, mit dem Sie experimentieren könnten.

+0

Das ist, was geschieht. Oder ist Ihr Beispiel, was Ihr EDIT beabsichtigt zu entwerten? – Andrew

+0

Entschuldigung, es ist ein schreckliches Beispiel, ein anderes Problem behoben. Will versuchen und später besser erklären. – Emile

1

Da Sie eine GestureDetector verwenden, implementieren Sie SimpleGestureDetector.onLongPress(MotionEvent e) für die Verarbeitung langer Klicks. Sie können jedoch das Listenelement nicht kennen, das von dort lange gedrückt wurde, also müssen Sie es von der normalen onItemLongClick() erinnern.

class MyGestureDetector extends SimpleOnGestureListener { 
    ... 
    @Override public void onLongPress(MotionEvent e) { 
     if (longClickedItem != -1) { 
      Toast.makeText(MainActivity.this, "Long click!", Toast.LENGTH_LONG).show(); 
     }   
    } 
} 

int longClickedItem = -1; 

@Override 
public boolean onItemLongClick(AdapterView<?> list, View view, int position, long id) { 
    longClickedItem = position; 
    return true; 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // Reset longclick item if new touch is starting 
    if (event.getAction()==MotionEvent.ACTION_DOWN) { 
     longClickedItem = -1; 
    } 

    if (mGestureDetector.onTouchEvent(event)) 
     return true; 
    else 
     return false; 
} 

Ich habe das getestet und es scheint gut zu funktionieren.

+0

Vielen Dank für Ihre Antwort. Ich werde es versuchen. Ich sollte beachten, dass, während ein langer Druck ist, was aktiviert wird und was ich bemerkt habe, was ich wirklich gerne geschehen würde, wäre kein Gestenverlust, wenn jemand wischt. Es gibt ein paar andere Probleme, vor allem mit Android-Handys, die das iPhone End-of-List-Animationen und dergleichen tun können. Das eigentliche Problem ist, dass das Wischen andere Gesten an die Liste sendet; und ich weiß nicht, wie ich das stoppen kann. – Andrew

+0

Ich habe es gerade versucht und es verhindert, dass der lange Klick ausgeführt wird, wenn ich wische, obwohl das Element, von dem Ihr Finger stammt, gelb hervorhebt; so ein Teil der Geste ist offensichtlich zu der Liste Leaking – Andrew

+0

Versuchen Sie, list.cancelLongPress() aufrufen, wenn der Gesten-Detektor True zurückgibt ... –

1

Sie gehen Ihre gestureDetector und setzen

mGestureDetector.setIsLongpressEnabled(false); 

Dies verhindert, dass lange Druckereignisse erkannt werden.

0

Ich entwickelte eine benutzerdefinierte Komponente abgeleitet von horizontalScrollView, die dies tut. Ich habe listViews wie das Kind sieht und wischen ohne langes Drücken. Es wird von einem listAdapter unterstützt, der alles sein kann, was Sie wollen (ArrayAdapter, CursorAdapter ...) Es lädt bis zu drei untergeordnete Ansichten und dann beim Spiegeln, tauscht sie einfach auf beiden Seiten. Das meiste davon wird aus ListView zusammengefügt und muss neu strukturiert werden. Es ist viel zu lange, um hier direkt zu posten.

http://pastie.org/1480091

0

Entfernen Sie Ihre getListView().setOnItemLongClickListener

Fügen Sie in Ihrer Klasse MyGestureDetector:

public void onLongPress(MotionEvent e) { 
    final int position = getListView().pointToPosition((int) e.getX(), 
      (int) e.getY()); 
    // what you want do 
    super.onLongPress(e); 
}