Android: Greifen Sie über eine ListView auf untergeordnete Ansichten zu

108

Ich muss die Pixelposition eines Elements in einer Liste herausfinden, die mit a angezeigt wurde ListView. Es scheint, als sollte ich eine der Textansichten herunterladen und dann verwenden getTop(), aber ich kann nicht herausfinden, wie ich eine untergeordnete Ansicht von einer bekomme ListView.

Update: Die untergeordneten ViewGroupElemente von entsprechen nicht 1: 1 den Elementen in der Liste, z ListView. Stattdessen ViewGroupentsprechen die untergeordneten Elemente nur den Ansichten, die gerade sichtbar sind. So getChildAt()arbeitet auf einem Index, der auf die innere ist ViewGroupund nicht unbedingt etwas mit der Position in der Liste zu tun haben , dass die ListViewAnwendungen.

Lack
quelle

Antworten:

215

Siehe: Android ListView: Datenindex des sichtbaren Elements abrufen und mit einem Teil der obigen Antwort von Feet kombinieren, kann Ihnen Folgendes geben:

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

Der Vorteil ist, dass Sie nicht über die untergeordneten Elemente von ListView iterieren, was zu einem Leistungseinbruch führen könnte.

Joe
quelle
10
Tolle Antwort, funktioniert aber nicht ganz richtig, wenn Sie Header-Ansichten in Ihrer Liste haben. Die Aufgabe firstPositionsollte sein int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();, dies zu beheben.
Pospi
@pospi: danke, guter Punkt! Ich habe meine Antwort aktualisiert, um dies zu berücksichtigen.
Joe
Gute Antwort und funktioniert in den meisten Fällen, aber ich verstehe nicht, warum Sie glauben, dass untergeordnete Ansichten in der Reihenfolge angezeigt werden, in der sie in der Reihe der untergeordneten Ansichten enthalten sind. Wie können wir sicher sein, dass die erste Ansicht nicht die letzte sichtbare Ansicht darstellt, da Ansichten wiederverwendet werden können?
Victor Denisov
2
@ VictorDenisov: Dies kann nur auf dem UI-Thread passieren; Daher wird der UI-Thread blockiert, während dieser Code ausgeführt wird. Daher sind die untergeordneten Ansichten stationär und werden nicht geändert. ListViewist bereits um nach dem Recycling alten „Bewegen“ die Ansichten Kind Handhabung convertView, etc, so dass Sie kann garantiert werden , dass ListView.getChildAt(0) ist der erste angebrachte Blick aus dem Adapter in der Tat. Es ist möglicherweise nicht vollständig sichtbar (und möglicherweise überhaupt nicht sichtbar, abhängig von ListViewder Schwelle der "Sichtbarkeit", bevor eine Ansicht recycelt wird, die als "aus der Ansicht gescrollt" betrachtet wird)
Joe,
1
@Matheus so funktioniert Android ListView nicht. Wenn sich das Listenelement außerhalb des Bildschirms befindet, wurde seine Ansicht bereits recycelt und für eines der anderen Listenelemente, die auf dem Bildschirm angezeigt werden, wiederverwendet . Sie sollten überlegen, wie Sie ListView verwenden, wenn dies erforderlich ist.
Joe
17

Dieser Code ist einfacher zu verwenden:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }
Kalimah
quelle
9
funktioniert nicht immer. getChildAt zählt ab der ersten sichtbaren Zeile, nicht vom Anfang der Daten.
SteelBytes
13
Das ViewID-Argument ist verwirrend. Es ist ein Index (oder eine Position). Die Ansichts-ID ist eine völlig beliebige Ganzzahl, die vom aapt-Tool generiert wird.
Johan Pelgrim
6

Bei einer schnellen Suche in den Dokumenten nach der ListView-Klasse wurden die von ViewGroup geerbten Methoden getChildCount () und getChildAt () gefunden. Können Sie sie mit diesen durchlaufen? Ich bin mir nicht sicher, aber es ist einen Versuch wert.

Fand es hier

Füße
quelle
1
Ich habe es versucht, um eine Auswahl zu treffen. Es funktioniert normalerweise, aber manchmal gibt es Fehler, die einzeln auftreten, und es ist nicht zuverlässig. Ich würde es nicht empfehlen.
Timmmm
Danke Timmmm, ich hatte es nicht wirklich ausprobiert, sondern nur in den Dokumenten gefunden.
Füße
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));
            }
        }
    }
});

Erstellen Sie grundsätzlich zwei Drawables - eines, das transparent ist, und eines, das die gewünschte Farbe hat. Fordern Sie den Fokus an der angeklickten Position ( int positionwie definiert) an und ändern Sie die Farbe der Zeile. Gehen Sie dann durch das übergeordnete Element ListViewund ändern Sie alle anderen Zeilen entsprechend. Dies gilt, wenn ein Benutzer listviewmehrmals auf die Schaltfläche klickt . Dies erfolgt mit einem benutzerdefinierten Layout für jede Zeile in der ListView. (Sehr einfach, erstellen Sie einfach eine neue Layoutdatei mit einem TextView- nicht fokussierbar oder anklickbar!).

Kein benutzerdefinierter Adapter erforderlich - verwenden ArrayAdapter

Wir s
quelle
getChildAt ist relativ zu aktuell gescrollten Elementen. Dies funktioniert nicht mehr, wenn Sie Ihre Liste nur ein wenig scrollen.
Nurettin
4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Milaaaad
quelle
1
Ausarbeiten ein wenig
innoSPG
-9

Dies setzt voraus, dass Sie die Position des Elements in der ListView kennen:

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

Dann sollten Sie in der Lage sein, getLeft () und getTop () aufzurufen, um die Elemente auf der Bildschirmposition zu bestimmen.

Jasonhudgins
quelle
43
getView()wird intern von der ListView aufgerufen, wenn die Liste gefüllt wird. Sie sollten es nicht verwenden, um die Ansicht an dieser Position in der Liste abzurufen, da das Aufrufen getView()mit null für convertViewbewirkt, dass der Adapter eine neue Ansicht aus der Layoutressource des Adapters aufbläst (erhält nicht die Ansicht, die bereits angezeigt wird).
Joe
1
Die gerade Position ist eine Position im visuellen Bildschirm, nicht die Position der Datenquelle des Adapters.
Vikas
@jasonhudgins Dies ist die Methode, die ich verwendet habe, weil ich dachte, sie sei die beste, aber wenn ich versuche, einen Fortschrittsbalken in der untergeordneten Ansicht unsichtbar zu machen, wurden stattdessen alle Fortschrittsbalken in listvew unsichtbar ........ all in Alle akzeptierten Antworten haben es geschafft
Edijae Crusar