Android: accedi alle visualizzazioni figlio da ListView


108

Ho bisogno di scoprire la posizione dei pixel di un elemento in un elenco che è stato visualizzato utilizzando un file ListView. Sembra che dovrei prendere uno dei TextView e poi usarlo getTop(), ma non riesco a capire come ottenere una visualizzazione per bambini di un file ListView.

Aggiornamento: gli elementi secondari di ViewGroupnon corrispondono 1 a 1 con gli elementi nell'elenco, per un file ListView. Invece, ViewGroupi figli di corrispondono solo a quelle viste che sono visibili al momento. Quindi getChildAt()opera su un indice interno a ViewGroupe non ha necessariamente nulla a che fare con la posizione nell'elenco che ListViewutilizza.

Risposte:


215

Vedi: Android ListView: ottieni l'indice dei dati dell'elemento visibile e combinalo con una parte della risposta di Feet sopra, può darti qualcosa come:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

Il vantaggio è che non stai iterando sui figli di ListView, il che potrebbe subire un calo delle prestazioni.


10
Ottima risposta, ma non funziona bene quando hai visualizzazioni di intestazione nel tuo elenco. Il compito firstPositiondovrebbe essere int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();quello di risolvere questo problema.
pospi

@pospi: grazie, buon punto! Ho aggiornato la mia risposta per tenerne conto.
Joe

Buona risposta e funziona nella maggior parte dei casi, ma non capisco perché ritieni che le visualizzazioni figlio vengano visualizzate nell'ordine in cui sono nella matrice delle visualizzazioni figlio. Poiché le viste possono essere riutilizzate, come possiamo essere sicuri che la prima vista non rappresenti l'ultima vista visibile?
Victor Denisov

2
@VictorDenisov: questo può accadere solo sul thread dell'interfaccia utente; pertanto il thread dell'interfaccia utente verrà bloccato durante l'esecuzione di questo codice, quindi le visualizzazioni figlio sono fisse e non verranno modificate. ListViewsta già gestendo lo "spostamento" delle viste secondarie dopo aver riciclato i vecchi convertView, ecc., così puoi essere certo che ListView.getChildAt(0) è in effetti la prima vista collegata dall'adattatore. Potrebbe non essere completamente visibile (e potrebbe anche non essere affatto visibile, a seconda ListViewdella soglia di "visibilità" di prima di riciclare una vista che considera "fatta scorrere fuori dalla vista")
Joe

1
@ Matheus non è così che funziona Android ListView. Se l'elemento dell'elenco è fuori dallo schermo, la sua visualizzazione è già stata riciclata e riutilizzata per uno degli altri elementi dell'elenco che sono sullo schermo. Dovresti ripensare a come stai usando ListView se questo è un requisito.
Joe

17

Questo codice è più facile da usare:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }

9
non funziona sempre. getChildAt conta dalla prima riga visibile, non dalla parte superiore dei dati.
SteelBytes

13
L'argomento ViewID crea confusione. È un indice (o una posizione). L'ID vista è un numero intero completamente arbitrario generato dallo strumento aapt.
Johan Pelgrim

6

Una rapida ricerca dei documenti per la classe ListView ha portato alla luce i metodi getChildCount () e getChildAt () ereditati da ViewGroup. Puoi iterare attraverso di loro usando questi? Non ne sono sicuro, ma vale la pena provare.

L'ho trovato qui


1
Ho provato questo, per fare le selezioni. Di solito funziona, ma a volte ci sono errori off-by-one e non è affidabile. Non lo consiglierei.
Timmmm

Grazie Timmmm, in realtà non l'avevo provato, l'ho trovato solo nei documenti.
Piedi

5
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

Fondamentalmente, crea due Drawable : uno trasparente e un altro del colore desiderato. Richiedi il focus nella posizione cliccata ( int positioncome definita) e cambia il colore di detta riga. Quindi attraversa il genitore ListViewe modifica tutte le altre righe di conseguenza. Questo tiene conto di quando un utente fa clic su listviewpiù volte. Questo viene fatto con un layout personalizzato per ogni riga nel file ListView. (Molto semplice, crea un nuovo file di layout con a TextView- non impostare attivabile o cliccabile!).

Nessun adattatore personalizzato richiesto: utilizzare ArrayAdapter


getChildAt è relativo agli elementi di scorrimento correnti. Questo smetterà di funzionare se scorri solo un po 'l'elenco.
nurettin

4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);

1
Elaborare un po '
innoSPG

-9

Ciò presuppone che tu conosca la posizione dell'elemento in ListView:

  View element = listView.getListAdapter().getView(position, null, null);

Quindi dovresti essere in grado di chiamare getLeft () e getTop () per determinare la posizione degli elementi sullo schermo.


43
getView()viene chiamato internamente da ListView, quando si popola l'elenco. Non dovresti usarlo per ottenere la vista in quella posizione nell'elenco, poiché la chiamata getView()con null per le convertViewcause dell'adattatore per gonfiare una nuova vista dalla risorsa di layout dell'adattatore (non ottiene la vista che è già visualizzata).
Joe

1
La posizione uniforme sarà una posizione nello schermo visivo, non la posizione dell'origine dati dell'adattatore.
Vikas

@jasonhudgins Questo è il metodo che ho usato perché pensavo fosse il migliore, ma quando provo a rendere invisibile una barra di avanzamento nella vista figlio, invece ha reso tutte le barre di avanzamento in listvew invisibili ........ tutto in tutte le risposte accettate hanno funzionato
Edijae Crusar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.