Verwenden eines ListAdapters zum Füllen eines LinearLayout in einem ScrollView-Layout

Lesezeit: 10 Minuten

Benutzer-Avatar
Stefan Hot

Ich stehe vor einem sehr häufigen Problem: Ich habe eine Aktivität angelegt und jetzt stellt sich heraus, dass darin einige Elemente angezeigt werden sollten ScrollView. Der normale Weg, dies zu tun, wäre, das Vorhandene zu verwenden ListAdapterverbinden Sie es mit a ListView und BOOM Ich hätte meine Artikelliste.

ABER Sie sollten keine Verschachtelung platzieren ListView in einem ScrollView da es das Scrollen vermasselt – sogar Android Lint beschwert sich darüber.

Also hier meine Frage:

Wie verbinde ich a ListAdapter zu einem LinearLayout oder etwas ähnliches?

Ich weiß, dass diese Lösung nicht für viele Elemente skaliert, aber meine Listen sind sehr kurz (< 10 Elemente), sodass die Wiederverwendung von Ansichten nicht wirklich erforderlich ist. In Bezug auf die Leistung kann ich damit leben, alle Ansichten direkt in die zu platzieren LinearLayout.

Eine Lösung, die ich mir ausgedacht habe, wäre, mein vorhandenes Aktivitätslayout im HeaderView-Abschnitt der zu platzieren ListView. Aber das fühlt sich an, als würde man diesen Mechanismus missbrauchen, also suche ich nach einer saubereren Lösung.

Ideen?

AKTUALISIEREN: Um die richtige Richtung zu inspirieren, füge ich ein Beispiellayout hinzu, um mein Problem zu zeigen:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/news_detail_layout"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical"
              android:visibility="visible">


    <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#FFF"
            >

        <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical"
                android:paddingLeft="@dimen/news_detail_layout_side_padding"
                android:paddingRight="@dimen/news_detail_layout_side_padding"
                android:paddingTop="@dimen/news_detail_layout_vertical_padding"
                android:paddingBottom="@dimen/news_detail_layout_vertical_padding"
                >

            <TextView
                    android:id="@+id/news_detail_date"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:gravity="center_horizontal"
                    android:text="LALALA"
                    android:textSize="@dimen/news_detail_date_height"
                    android:textColor="@color/font_black"
                    />

            <Gallery
                    android:id="@+id/news_detail_image"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:paddingTop="5dip"
                    android:paddingBottom="5dip"
                    />

            <TextView
                    android:id="@+id/news_detail_headline"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:gravity="center_horizontal"
                    android:text="Some awesome headline"
                    android:textSize="@dimen/news_detail_headline_height"
                    android:textColor="@color/font_black"
                    android:paddingTop="@dimen/news_detail_headline_paddingTop"
                    android:paddingBottom="@dimen/news_detail_headline_paddingBottom"
                    />

            <TextView
                    android:id="@+id/news_detail_content"
                    android:layout_height="wrap_content"
                    android:layout_width="fill_parent"
                    android:text="Here comes a lot of text so the scrollview is really needed."
                    android:textSize="@dimen/news_detail_content_height"
                    android:textColor="@color/font_black"
                    />

            <!---
                HERE I NEED THE LIST OF ITEMS PROVIDED BY THE EXISTING ADAPTER. 
                They should be positioned at the end of the content, so making the scrollview smaller is not an option.
            ---->                        

        </LinearLayout>
    </ScrollView>
</LinearLayout>

AKTUALISIERUNG 2 Ich habe die Überschrift geändert, um sie verständlicher zu machen (habe eine Ablehnung bekommen, doh!).

  • Haben Sie jemals eine schöne, saubere Lösung für dieses Problem gefunden? Ich sehe, dass Google es in seinem Play Store für Bewertungen verwendet. Weiß jemand wie sie das machen?

    – Zapnologica

    15. Oktober 2014 um 16:58 Uhr

Benutzer-Avatar
rauchen

Sie sollten Ihre Artikel wahrscheinlich einfach manuell hinzufügen LinearLayout:

LinearLayout layout = ... // Your linear layout.
ListAdapter adapter = ... // Your adapter.

final int adapterCount = adapter.getCount();

for (int i = 0; i < adapterCount; i++) {
  View item = adapter.getView(i, null, null);
  layout.addView(item);
}

BEARBEITEN: Ich habe diesen Ansatz abgelehnt, als ich ungefähr 200 nicht-triviale Listenelemente anzeigen musste, es ist sehr langsam – Nexus 4 brauchte ungefähr 2 Sekunden, um meine “Liste” anzuzeigen, das war nicht akzeptabel. Also wandte ich mich Flos Ansatz mit Kopfzeilen zu. Es funktioniert viel schneller, da Listenansichten bei Bedarf erstellt werden, wenn der Benutzer scrollt, und nicht zum Zeitpunkt der Ansichtserstellung.

Fortsetzen: Das manuelle Hinzufügen von Ansichten zum Layout ist einfacher zu codieren (daher möglicherweise weniger bewegliche Teile und Fehler), leidet jedoch unter Leistungsproblemen. Wenn Sie also 50 oder mehr Ansichten haben, empfehle ich, den Header-Ansatz zu verwenden.

Beispiel. Grundsätzlich ändert sich das Aktivitäts- (oder Fragment-) Layout in etwa so (kein ScrollView mehr erforderlich):

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/my_top_layout"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>

Dann in onCreateView() (Ich werde ein Beispiel mit einem Fragment verwenden) Sie müssen eine Header-Ansicht hinzufügen und dann einen Adapter festlegen (ich nehme an, die Header-Ressourcen-ID ist header_layout):

ListView listView = (ListView) inflater.inflate(R.layout.my_top_layout, container, false);
View header = inflater.inflate(R.layout.header_layout, null);
// Initialize your header here.
listView.addHeaderView(header, null, false);

BaseAdapter adapter = // ... Initialize your adapter.
listView.setAdapter(adapter);

// Just as a bonus - if you want to do something with your list items:
view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // You can just use listView instead of parent casted to ListView.
    if (position >= ((ListView) parent).getHeaderViewsCount()) {
      // Note the usage of getItemAtPosition() instead of adapter's getItem() because
      // the latter does not take into account the header (which has position 0).
      Object obj = parent.getItemAtPosition(position);
      // Do something with your object.
    }
  }
});

  • Ja, das war die zweite Idee, die ich hatte, aber ich war mir nicht sicher ListAdapter und die ListView zaubert mehr hinter den Bildschirmen, was ich dann nicht manuell mache.

    – Stefan Hoth

    13. September 2012 um 12:49 Uhr

  • Natürlich macht ListView etwas Magie, zumindest Trennlinien zwischen Elementen, Sie müssten sie manuell hinzufügen, denke ich. ListAdapter (wenn es richtig implementiert ist) sollte nicht mehr zaubern.

    – rauchen

    13. September 2012 um 13:27 Uhr

  • Dies ist eine Ablehnung für mich. Speicherprobleme irgendjemand? Es gibt einen Grund, warum wir Adapter verwenden …

    – Kevin Parker

    2. Mai 2013 um 18:14 Uhr

  • Hat noch jemand Probleme mit der Aktualisierung der Ansichten mit dem Adapter notifyDataSetChanged Methode? Dies funktioniert gut auf einem anderen Adapter, den ich an einen angeschlossen habe ListViewaber es scheint nicht mit dem zu funktionieren, das ich an a angeschlossen habe LinearLayout.

    – Witzefe

    12. November 2013 um 4:48 Uhr


  • Das ist einer der Gründe, warum ich Android hasse. Ich verstehe nicht, warum Sie komplizierte Lösungen implementieren müssen oder unter Leistungsproblemen leiden.

    – IARI

    27. Februar 2017 um 19:13 Uhr

Ich würde bei der Header-View-Lösung bleiben. Daran ist nichts auszusetzen. Im Moment implementiere ich eine Aktivität mit genau dem gleichen Ansatz.

Offensichtlich ist der “Artikelteil” eher dynamisch als statisch (variierende Artikelanzahl vs. feste Artikelanzahl usw.), ansonsten werden Sie überhaupt nicht daran denken, einen Adapter zu verwenden. Wenn Sie also einen Adapter benötigen, verwenden Sie die ListView.

Das Implementieren einer Lösung, die ein LinearLayout aus einem Adapter füllt, ist letztendlich nichts anderes als das Erstellen einer ListView mit einem benutzerdefinierten Layout.

Nur meine 2 Cent.

  • Ein Nachteil dieses Ansatzes besteht darin, dass Sie fast Ihr gesamtes Aktivitätslayout (siehe oben) in ein anderes Layout verschieben müssen, damit Sie es als ListHeaderView referenzieren und ein weiteres Layout erstellen können, das nur die enthält ListView. Ich bin mir nicht sicher, ob mir diese Patch-Arbeit gefällt.

    – Stefan Hoth

    13. September 2012 um 12:47 Uhr

  • Ja, ich weiß, was Sie meinen, bevor ich anfing, diesen Ansatz zu verwenden, mochte ich auch die Idee nicht, mein Aktivitätslayout in mehrere Dateien aufzuteilen. Aber als ich sah, dass das Gesamtlayout so aussah, wie ich es erwartet hatte, störte mich die Trennung nicht, da es nur in zwei Dateien aufgeteilt ist. Eines müssen Sie beachten, die ListView darf keine leere Ansicht haben, da dies Ihren Listenkopf ausblendet, wenn keine Listenelemente vorhanden sind.

    – Flo

    13. September 2012 um 14:00 Uhr

  • Auch wenn Sie mehrere Listen auf einer Seite haben möchten, funktioniert dies nicht wirklich. Hat jemand ein Beispiel für eine benutzerdefinierte Adapteransicht, die Elemente in eine “flache” Liste ausgibt, dh eine, die nicht scrollt?

    – Murtuza

    12. Juli 2014 um 20:45 Uhr

Stellen Sie Ihre Ansicht auf main.xml onCreate ein und füllen Sie sie dann aus row.xml auf

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="450dp" >

        <ListView
            android:id="@+id/mainListView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_above="@+id/size"
            android:layout_below="@+id/editText1"
            android:gravity="fill_vertical|fill_horizontal"
            android:horizontalSpacing="15dp"
            android:isScrollContainer="true"
            android:numColumns="1"
            android:padding="5dp"
            android:scrollbars="vertical"
            android:smoothScrollbar="true"
            android:stretchMode="columnWidth" >

</ListView>

    <TextView
        android:id="@+id/size"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:background="#ff444444"
        android:gravity="center"
        android:text="TextView"
        android:textColor="#D3D3D3"
        android:textStyle="italic" />

    </EditText>

</RelativeLayout> 

Zeile.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" 
  android:paddingTop="3dp">

<TextView
  android:id="@+id/rowTextView"
  android:layout_width="0dip"
  android:layout_height="41dp"
  android:layout_margin="4dp"
  android:layout_weight="2.83"
  android:ellipsize="end"
  android:gravity="center_vertical"
  android:lines="1"
  android:text="John Doe"
  android:textColor="@color/color_white"
  android:textSize="23dp" >
</TextView>

</LinearLayout>

  • Ich glaube du hast die Frage falsch verstanden. Er möchte keine Liste mit LinearLayouts füllen.

    – Flo

    13. September 2012 um 12:13 Uhr

  • “Wie verbinde ich einen ListAdapter mit einem LinearLayout oder ähnlichem?” Ich beantworte nur, was der OP gefragt hat

    – Fascheich

    13. September 2012 um 12:17 Uhr

  • Nein, er möchte keine ListView verwenden. Er möchte nur einen Adapter verwenden und damit ein LinearLayout mit Einträgen füllen.

    – Flo

    13. September 2012 um 12:29 Uhr

  • Danke für deine Antwort, aber @Flo ist richtig. ich kippen Verwenden Sie eine ListView, da das äußere Layout bereits eine ScrollView ist. Bitte überprüfen Sie meinen Text und das Musterlayout.

    – Stefan Hoth

    13. September 2012 um 13:30 Uhr

  • Warum wird diese scrollView benötigt?

    – Fascheich

    13. September 2012 um 13:36 Uhr

Ich verwende folgenden Code, mit dem die Adapterfunktionalität repliziert wird ViewGroup und TabLayout. Das Gute daran ist, dass wenn Sie Ihre Liste ändern und erneut binden, dies nur geänderte Elemente betrifft:

Verwendungszweck:

val list = mutableListOf<Person>()
layout.bindChildren(list, { it.personId }, { bindView(it) }, {d, t ->bindView(d, t)})
list.removeAt(0)
list+=newPerson
layout.bindChildren(list, { it.personId }, { bindView(it) }, {d, t ->bindView(d, t)})

Zum ViewGroups:

fun <Item, Key> ViewGroup.bindChildren(items: List<Item>, id: (Item) -> Key, view: (Item) -> View, bind: (Item, View) -> Unit) {
    val old = children.map { it.tag as Key }.toList().filter { it != null }
    val new = items.map(id)

    val add = new - old
    val remove = old - new
    val keep = new.intersect(old)

    val tagToChildren = children.associateBy { it.tag as Key }
    val idToItem = items.associateBy(id)

    remove.forEach { tagToChildren[it].let { removeView(it) } }
    keep.forEach { bind(idToItem[it]!!, tagToChildren[it]!!) }
    add.forEach { id -> view(idToItem[id]!!).also { it.tag = id }.also { addView(it, items.indexOf(idToItem[id])) } }
}

Zum TabLayout Ich habe das:

fun <Item, Key> TabLayout.bindTabs(items: List<Item>, toKey: (Item) -> Key, tab: (Item) -> TabLayout.Tab, bind: (Item, TabLayout.Tab) -> Unit) {
    val old = (0 until tabCount).map { getTabAt(it)?.tag as Key }
    val new = items.map(toKey)

    val add = new - old
    val remove = old - new
    val keep = new.intersect(old)

    val tagToChildren = (0 until tabCount).map { getTabAt(it) }.associateBy { it?.tag as Key }
    val idToItem = items.associateBy(toKey)

    remove.forEach { tagToChildren[it].let { removeTab(it) } }
    keep.forEach { bind(idToItem[it]!!, tagToChildren[it]!!) }
    add.forEach { key -> tab(idToItem[key]!!).also { it.tag = key }.also { addTab(it, items.indexOf(idToItem[key])) } }
}

1310770cookie-checkVerwenden eines ListAdapters zum Füllen eines LinearLayout in einem ScrollView-Layout

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy