2011-01-13 12 views
10

Mam działanie, które zawiera ViewFlipper. ViewFlipper zawiera 2 układy, z których oba są po prostu ListViews.Problemy z wykrywaniem gestów na liście ListView

Pomysł polega na tym, że mam dwie listy i aby poruszać się między nimi, użyłbym poziomego przesunięcia.

Mam to działa. Jednak, jeśli kiedykolwiek pojawi się lista elementów, na których znajduje się palec, gdy rozpoczyna się machnięcia, ten element będzie również długo klikany.

Oto odpowiedni kod mam:

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); 

    } 

    … 
} 

Gdybym zmienić "return true;" oświadczenie od GestureDetector do "return false;", nie dostaję długich kliknięć. Niestety, uzyskuję regularne kliknięcia.

Czy ktoś wie, jak sobie z tym poradzić?

Odpowiedz

7

Wystarczy rzucić się w zupełnie inną odpowiedź z zupełnie innego podejścia ...

Zrobiłem własny widok nazwie SwipeView, jest to open source itp itd bla bla bla. Powinno to pozwolić robić to, co chcesz robić tak prosto, jak dzieje:

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

Nie trzeba zadzierać z detektorów o gest czy cokolwiek, a machnięcia palcem powinien postępować jak to zrobić ..

(To brzmi jak okropna reklama, proszę wybacz mi.To był długi dzień;)

Mają wspaniałe linki:

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

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

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

+0

Jest to podobne do ostatnio opracowanego komponentu, z tym wyjątkiem, że dodałem widok recyklingu do kopalni i jej wspierane przez listadapter. Zasadniczo, użyłem kępki kodu ListView i dołączałem go do niestandardowego gestu HorizontalScrollView, tak jak ty. – jfelectron

+0

Tak, pracuję nad dodaniem tego do SwipeView też! Ponadto, właśnie (dosłownie około 2 minuty temu) zauważyłem, że istnieje błąd z ListViews na SwipeView. Naprawiłem błąd i zaktualizowałem repozytorium git. https://github.com/fry15/uk.co.jasonfry.android.tools – jsonfry

+3

jfelectron jest jednak na GIThub? –

0

[EDYT.] Zdrapcie to całkowicie błędne.

Myślę, że musiałbyś zaktualizować tę część i wykryć, czy przewijasz w lewo lub w prawo, i powrócić do wartości true, jeśli jesteś w stanie przesuwania. Lub przynajmniej tam będę wyglądał pierwszy.

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

Kontynuując mój biedny przykład, przepraszam.

W systemie onTouch wierzę, że można przetestować event.getAction() i określić, czy nastąpiło długie kliknięcie. Jeśli tak, a ty w rzucaniu, powróć do prawdy, aby uchwycić długie kliknięcie.

Obawia się, że jest to raczej sugestia niż ostateczna odpowiedź.

Sprawdziłeś również inne na [metody], które można przesłonić z SimpleOnGestureListener. Po prostu sprawdzone i może być coś, z czym możesz eksperymentować.

+0

To, co się dzieje. A może to twój przykład, który EDIT zamierza unieważnić? – Andrew

+0

Przykro nam, to straszny przykład, naprawiając inny problem. Postaram się wyjaśnić lepiej później. – Emile

1

Ponieważ używasz GestureDetector, należy wykonać SimpleGestureDetector.onLongPress(MotionEvent e) dla obsługi długich kliknięć. Jednak nie możesz znać listy, która była od dawna stuknięta, więc musisz ją zapamiętać z normalnego onItemLongClick().

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; 
} 

Testowałem to i wygląda na to, że działa dobrze.

+0

Dziękuję za odpowiedź. Spróbuję. Powinienem zauważyć, że chociaż aktywna jest długa prasa i jest to, co zauważyłem, to, co naprawdę chciałbym się wydarzyć, nie ma przecieku gestów, jeśli ktoś przesuwa. Jest kilka innych problemów, szczególnie z telefonami z Androidem, które mogą wykonywać animacje na końcu listy iPhone'a i inne. Prawdziwym problemem jest to, że przesuwanie przesyła inne gesty do listy; i nie wiem, jak to zatrzymać. – Andrew

+0

Właśnie próbowałem tego i zapobiega to wykonywaniu długiego kliknięcia podczas przesuwania palca, chociaż element, z którego pochodzi Twój palec, podświetla kolor żółty; więc pewna część gestu jest widocznie wyciekła na listę – Andrew

+0

Spróbuj wywołać list.cancelLongPress(), jeśli detektor ruchu zwróci wartość true ... –

1

odejść, Ty i Twój gestureDetector zestaw

mGestureDetector.setIsLongpressEnabled(false); 

Zapobiega to wykrywaniu długich zdarzeń prasowych.

0

Opracowałem niestandardowy komponent pochodzący z horizontalScrollView, który to robi. Mam listViews jako widok podrzędny i przesuń bez długich naciśnięć. Jest wspierany przez listAdapter, który może być wszystkim, czego potrzebujesz (ArrayAdapter, CursorAdapter ...) Ładuje do trzech widoków podrzędnych, a następnie po odwróceniu, po prostu zamienia je po obu stronach. Większość tego jest kanged z ListView i musi być refaktoryzowana. Jest zbyt długi, aby publikować tutaj bezpośrednio.

http://pastie.org/1480091

0

Usuń swoje getListView().setOnItemLongClickListener

Dodaj w swojej klasie MyGestureDetector:

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