2010-01-26 14 views
7

Ho implementato un codice di rilevamento dei gesti in modo da poter rilevare quando una riga nella mia listview (che si trova in un FrameLayout) è stata strisciata.Come ottenere la posizione (sullo schermo) della riga in listview

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
    if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { 
     int itemId = MainActivity.this.getListView().pointToPosition((int) e1.getX(),(int) e1.getY()); 
     Offer order = (Offer)MainActivity.this.getListView().getAdapter().getItem(itemId); 
     View v = MainActivity.this.getListView().getChildAt(itemId); 
    } 
} 

voglio visualizzare una vista sopra la parte superiore della riga strisciato con una serie di opzioni sensibili al contesto per quella riga.

miei problemi è che i seguenti metodi:

v.getTop() 
v.getBottom() 

ritorno valori corretti solo prima che la vista è stato fatto scorrere. Probabilmente potrei fare qualche calcolo per calcolare gli offset usando le posizioni di scorrimento ecc. Ma ho anche notato che ottengo solo valori quando faccio scorrere una riga che è visibile sullo schermo per cominciare. Se faccio scorrere verso il basso l'elenco e poi faccio scorrere una riga (che non era originariamente fuori dallo schermo), questi metodi restituiscono valori nulli.

I metodi indicati sembrano soffrire dello stesso problema ...

v.getLocationOnScreen(loc) 
v.getLocationInWindow(loc) 

In definitiva, sto cercando di trovare la distanza tra la parte superiore del listView visibile e la fila che è stato fregato. Quindi userò questa distanza per aggiungere una vista al FrameLayout genitore con il padding dell'altezza appropriato (in modo che copra la riga strisciata).

Qualsiasi aiuto sarebbe molto apprezzato!

risposta

17

Esistono due modi per indicizzare gli oggetti ListView, per posizione nell'adattatore o per posizione visibile sullo schermo. Un oggetto sarà sempre nella stessa posizione all'interno dell'adattatore (a meno che non si modifichi l'elenco). L'indice in view.getChildAt() varierà a seconda di cosa è visibile sullo schermo.

La posizione restituita da pointToPosition è la posizione all'interno dell'adattatore. Se si desidera ottenere la visualizzazione fisica, è necessario tenere conto se la vista viene scorsa. Prova questo:

int adapterIndex = MainActivity.this.getListView().pointToPosition((int) e1.getX(),(int) e1.getY()); 
int firstViewItemIndex = MainActivity.this.getListView().getFirstVisiblePosition(); 
int viewIndex = adapterIndex - firstViewItemIndex; 
View v = MainActivity.this.getListView().getChildAt(viewIndex); 
+0

Grazie per la risposta. In realtà non sto tenendo traccia degli oggetti vista. In fase di esecuzione, ottengo dinamicamente la fila quando viene strisciata. Quindi faccio le chiamate sopra per cercare di capire la sua posizione sullo schermo. Non sto cambiando la riga stessa Voglio semplicemente visualizzare una vista sopra la parte superiore della riga. Ho un listener di scorrimento che rimuove la nuova vista non appena si scorre di nuovo l'elenco. Una dimostrazione della funzione può essere vista in questa demo di tweetie 2 per iPhone: http://www.youtube.com/watch?v=Vxjj3F5MCpQ#t=1m12s – Damian

+0

Potresti approfondire come si ottiene dinamicamente una sospensione della riga in fase di esecuzione, quando viene strisciata? –

+0

Utilizzo di GestureDetector e GestureListener in ListView. Ho aggiornato lo snippet di codice sopra per includere il metodo onFling (e params) che viene chiamato quando un utente fa scorrere il dito sulla lista. Alcune semplici operazioni matematiche vengono utilizzate per verificare che l'utente stia scorrendo da sinistra a destra, quindi pointToPosition viene utilizzato per trovare a quale riga corrisponde il passaggio. – Damian

1

Ho risolto questo, ma sembra un po 'un hack e probabilmente non è l'implementazione più efficiente. Sicuramente ci deve essere un modo più pulito per farlo usando le API di Android?

Nel codice qui sotto, ho aggiunto un HashMap al mio ArrayAdaptor per tenere traccia di quali sulle viste a schermo stanno tenendo le righe (dal momento che questi sono riciclati come si scorre l'elenco)

Tutte le modifiche che ho fatto a il mio adattatore originale è stato commentato di seguito.

+0

Ho provato questa soluzione e non ha funzionato per me. Non ho potuto modificare la vista restituita. Comunque, usando getChildAt il lavoro sulla lista ha funzionato nel mio caso. Non sono sicuro del motivo per cui non è stato possibile modificare la vista restituita utilizzando questo metodo. – Andy

+0

In realtà getChildAt non ha funzionato per me per lo stesso motivo per cui non ha funzionato per te, così ho finito per usare l'altra risposta in questa pagina e questo ha funzionato. – Andy

1

Questo è il modo migliore che ho trovato per rilevare quale riga è stata toccata.

  Rect rect = new Rect(); 
      int childCount = mListView.getChildCount(); 
      int[] listViewCoords = new int[2]; 
      mListView.getLocationOnScreen(listViewCoords); 
      int listX = (int) event.getRawX() - listViewCoords[0]; 
      int listY = (int) event.getRawY() - listViewCoords[1]; 

      View child; 
      for (int i = 0; i < childCount; i++) { 
       child = mListView.getChildAt(i); 
       child.getHitRect(rect); 
       if (rect.contains(listX, listY)) { 
        mDownView = child; 
        break; 
       } 
      } 

È possibile utilizzarlo nel metodo onTouch all'evento ACTION_DOWN. Saluti.

+0

Grazie. Tuttavia, getChildAt() restituisce il primo figlio ** visibile ** (e non il primo figlio nell'elenco). Per farlo funzionare è possibile utilizzare for (int i = 0; i Zach

Problemi correlati