2011-01-13 12 views
10

Ho un'attività che contiene ViewFlipper. ViewFlipper include 2 layout, che sono essenzialmente solo ListViews.Problemi con il rilevamento di gesti su ListView

Quindi l'idea qui è che ho due elenchi e per navigare da uno all'altro userei uno scorrimento orizzontale.

Ho quello che funziona. Tuttavia, quale sia la lista di elementi in cui il tuo dito è attivo quando lo swipe inizia ad essere eseguito, quell'elemento verrà anche cliccato a lungo.

Ecco il relativo codice che ho:

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

    } 

    … 
} 

Se cambio il "return true;" dichiarazione da GestureDetector per "restituire falso;", non ottengo clic lunghi. Sfortunatamente, ricevo clic regolari.

Qualcuno sa come posso aggirare questo?

risposta

7

solo per gettare in una risposta completamente diverso con un approccio completamente diverso ...

Ho fatto una vista personalizzata denominata SwipeView, è open source ecc ecc bla bla bla. Esso dovrebbe permettere di fare quello che vuoi fare nel modo più semplice andare:

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

Non dovrete pasticciare con rilevatori gesto o nulla, e il il colpo dovrebbe seguire il dito, come si fa ..

(Si legge come una terribile pubblicità terribile, per favore scusami.E 'stata una lunga giornata;)

avere alcuni meravigliosi link:

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

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

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

+0

Questo è simile a un componente che ho sviluppato di recente, tranne che ho aggiunto il riciclo vista al mio e al suo supportato da un listAdapter. Fondamentalmente, ho inserito un gruppo di codice ListView e l'ho collegato a un orizzontale guidato da HorizontalScrollView come hai fatto tu. – jfelectron

+0

Sì, sto lavorando per aggiungerlo anche a SwipeView! Inoltre, ho appena (letteralmente, solo 2 minuti fa) notato che c'è un bug con ListViews su SwipeView. Ora ho corretto il bug e aggiornato il repository git. https://github.com/fry15/uk.co.jasonfry.android.tools – jsonfry

+3

jfelectron è tuo su GIThub? –

0

[EDIT] Scratch che, totalmente sbagliato.

Penso che dovresti aggiornare questa parte e rilevare se stavi scorrendo a sinistra oa destra e restituire true se eri in uno stato di swiping. O almeno è quello che guarderei prima.

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

Continuando con il mio povero esempio, mi dispiace.

All'interno di onTouch credo che sia possibile testare event.getAction() e determinare se si è verificato un clic lungo. Se ha, e il tuo in un movimento di lancio, restituisce true per catturare il clic lungo.

Paura che sia più un suggerimento che una risposta definitiva.

Inoltre è possibile controllare l'altro su [metodi] che è possibile sovrascrivere da SimpleOnGestureListener. Appena controllato e

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

potrebbe essere qualcosa che si potrebbe sperimentare.

+0

Questo è ciò che sta accadendo. O è il tuo esempio che cosa intende invalidare il tuo EDIT? – Andrew

+0

Scusa, è un terribile esempio, ho risolto un altro problema. Proverò a spiegare meglio dopo. – Emile

1

Poiché si sta utilizzando un GestureDetector, la cosa da fare è implementare SimpleGestureDetector.onLongPress(MotionEvent e) per la gestione dei clic lunghi. Tuttavia, non è possibile conoscere il listino che è stato premuto a lungo da lì, quindi è necessario ricordarlo dal normale 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; 
} 

Ho provato questo e sembra funzionare bene.

+0

Grazie per la risposta. Farò un tentativo. Devo notare che mentre una stampa lunga è ciò che viene attivato ed è ciò che ho notato, ciò che mi piacerebbe davvero accadere è che non ci siano perdite di gesti se qualcuno sta scorrendo. Ci sono alcuni altri problemi, specialmente con i telefoni Android che possono fare le animazioni di fine elenco di iPhone e così via. Il vero problema qui è che lo swiping sta inviando altri gesti alla lista; e non so come fermarlo. – Andrew

+0

Ho appena provato questo e impedisce il lungo click dall'esecuzione quando faccio scorrere, anche se l'oggetto con cui il dito è originato evidenzia il giallo; quindi qualche pezzo del gesto sta ovviamente perdendo nella lista – Andrew

+0

Prova a chiamare list.cancelLongPress() se il rilevatore di gesti restituisce true ... –

1

di partire il vostro gestureDetector e impostare

mGestureDetector.setIsLongpressEnabled(false); 

Ciò impedirà il rilevamento di eventi di stampa lunghi.

0

Ho sviluppato un componente personalizzato derivato da orizzontaleScrollView che esegue questa operazione. Ho listView come le visualizzazioni figlio e scorrere senza lunghe pressioni. E 'supportato da un listAdapter, che potrebbe essere qualsiasi cosa tu voglia (ArrayAdapter, CursorAdapter ...). Carica fino a tre visualizzazioni figlio e poi su flipping, le scambia semplicemente su entrambi i lati. La maggior parte di questo è modificata da ListView e deve essere sottoposta a refactoring. È troppo lungo per postare qui direttamente.

http://pastie.org/1480091

0

Rimuovere il getListView().setOnItemLongClickListener

Aggiungi nella tua classe MyGestureDetector:

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