So aktualisieren Sie eine ListView unter Android dynamisch [geschlossen]


159

Wie kann ich unter Android einen ListViewFilter basierend auf Benutzereingaben verwenden, bei dem die angezeigten Elemente basierend auf dem TextViewWert dynamisch aktualisiert werden ?

Ich suche so etwas:

-------------------------
| Text View             |
-------------------------
| List item             |
| List item             |
| List item             |
| List item             |
|                       |
|                       |
|                       |
|                       |
-------------------------

7
Ich nominiere für die Wiedereröffnung. Ich habe den Text aktualisiert, um dies zu einer Frage zu machen, und es ist eindeutig eine wertvolle Community-Ressource, da immer noch Antworten
eingehen

Bitte öffnen Sie die Frage erneut. Es ist eindeutig hilfreich.
SilentNot

Antworten:


286

Zunächst müssen Sie ein XML-Layout erstellen, das sowohl einen EditText als auch eine ListView enthält.

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- Pretty hint text, and maxLines -->
    <EditText android:id="@+building_list/search_box" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="type to filter"
        android:inputType="text"
        android:maxLines="1"/>

    <!-- Set height to 0, and let the weight param expand it -->
    <!-- Note the use of the default ID! This lets us use a 
         ListActivity still! -->
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" 
         /> 

</LinearLayout>

Dadurch wird alles richtig dargestellt, mit einem schönen EditText über der ListView. Erstellen Sie als Nächstes eine ListActivity wie gewohnt, fügen Sie jedoch einen setContentView()Aufruf in die onCreate()Methode ein, damit wir unser kürzlich deklariertes Layout verwenden. Denken Sie daran, dass wir die ListViewspeziell mit identifiziert haben android:id="@android:id/list". Dadurch können wir ListActivitywissen, welche ListViewwir in unserem deklarierten Layout verwenden möchten.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.filterable_listview);

        setListAdapter(new ArrayAdapter<String>(this,
                       android.R.layout.simple_list_item_1, 
                       getStringArrayList());
    }

Wenn Sie die App jetzt ausführen, sollte Ihre vorherige App ListViewmit einem schönen Feld oben angezeigt werden. Damit diese Box etwas tut, müssen wir die Eingabe daraus entnehmen und diese Eingabe die Liste filtern lassen. Während viele Leute versucht haben, dies manuell zu tun, enthalten die meisten ListView Adapter Klassen ein FilterObjekt, mit dem die Filterung automatisch durchgeführt werden kann. Wir müssen nur die Eingabe von der EditTextin die leiten Filter. Es stellt sich heraus, dass das ziemlich einfach ist. Fügen Sie diese Leitung zu Ihrem onCreate()Anruf hinzu, um einen Schnelltest durchzuführen

adapter.getFilter().filter(s);

Beachten Sie, dass Sie Ihre ListAdapterin einer Variablen speichern müssen, damit dies funktioniert. Ich habe meine ArrayAdapter<String>von früher in einer Variablen namens "Adapter" gespeichert .

Der nächste Schritt besteht darin, die Eingabe von der zu erhalten EditText. Dies erfordert tatsächlich ein wenig Nachdenken. Sie könnten eine OnKeyListener()zu Ihrer hinzufügen EditText. Dieser Listener empfängt jedoch nur einige Schlüsselereignisse . Wenn ein Benutzer beispielsweise "wyw" eingibt, empfiehlt der Vorhersagetext wahrscheinlich "eye". Bis der Benutzer entweder "wyw" oder "eye" wählt, erhalten Sie OnKeyListenerkein Schlüsselereignis. Einige mögen diese Lösung bevorzugen, aber ich fand sie frustrierend. Ich wollte jedes Schlüsselereignis, also hatte ich die Wahl, zu filtern oder nicht zu filtern. Die Lösung ist a TextWatcher. Erstellen Sie einfach und fügen Sie TextWatcherzu dem EditText, und der Pass ListAdapter Filtereiner Filteranforderung ändert dich der Text jedes Mal. Denken Sie daran, das TextWatcherIn zu entfernen OnDestroy()! Hier ist die endgültige Lösung:

private EditText filterText = null;
ArrayAdapter<String> adapter = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.filterable_listview);

    filterText = (EditText) findViewById(R.id.search_box);
    filterText.addTextChangedListener(filterTextWatcher);

    setListAdapter(new ArrayAdapter<String>(this,
                   android.R.layout.simple_list_item_1, 
                   getStringArrayList());
}

private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        adapter.getFilter().filter(s);
    }

};

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
}

7
Gibt es eine einfache Möglichkeit, ListView in "enthält" statt "beginnt mit" zu filtern, wie dies bei dieser Lösung der Fall ist?
Viktor Brešan

12
Viktor - Wenn die Wörter, an denen Sie interessiert sind, durch Leerzeichen getrennt sind, geschieht dies automatisch. Ansonsten nicht wirklich. Der wahrscheinlich einfachste Weg wäre, den Adapter durch Erweitern zu unterklassifizieren und die getFilter-Methode zu überschreiben, um ein von Ihnen definiertes Filterobjekt zurückzugeben. Siehe github.com/android/platform_frameworks_base/blob/master/core/... zu verstehen , wie die Standard ArrayFilter Werke - es wäre einfach 95% dieses Codes und Wechsellinien 479 und 486 zu kopieren
Hamy

2
Hamy, exzellente Berichterstattung! Ich habe jedoch eine Frage: Ich habe dies implementiert und nach jedem von mir eingegebenen Buchstaben verschwindet die ListView für einige Sekunden und kommt dann gefiltert zurück. Hast du das erlebt? Meine Intuition ist, dass ich mehr als 600 Elemente in der Liste habe, mit nicht trivialen toString () -Funktionen.
Lowellk

2
Im Querformat auf einem kleineren Bildschirm nimmt die EditText + -Tastatur den gesamten Bildschirm ein und die ListView ist nicht sichtbar! Irgendeine Lösung?
Martin Konicek

4
Ist das wirklich notwendig? > Denken Sie daran, den TextWatcher in OnDestroy ()
Jojo

10

Durch Ausführen des Programms wird eine Kraft geschlossen.

Ich habe die Leitung getauscht:

android: id = "@ + Gebäudeliste / Suchbox"

mit

android: id = "@ + id / search_box"

könnte das das problem sein Wofür ist die '@ + building_list'?


Johe, wenn du R.id.something sagst, existiert etwas in id, weil du android gesagt hast: id = "@ + id / search_box". Wenn Sie android sagen: id = "@ + building_list / search_box", können Sie im Code findViewById (R.building_list.search_box) aufrufen; Was ist die Ausnahme der obersten Ebene, die Sie erhalten? Dieser Code wird ohne Testkompilierung kopiert, daher habe ich wahrscheinlich irgendwo mindestens einen Fehler hinterlassen
Hamy

Hallo Hamy, Sie haben im Code mit "filterText = (EditText) findViewById (R.id.search_box)" @ + building_list / search_box "referenziert." Deshalb habe ich mich gefragt.
j7nn7k

1
Das Forceclose tritt auf, wenn mit der Eingabe begonnen wird. Teil des Fehlers: ERROR / AndroidRuntime (188): java.lang.NullPointerException 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at xxx.com.ListFilter $ 1. onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at android.widget.TextView $ ChangeWatcher.onTextChanged (TextView.java) : 6286)
j7nn7k

Johe, Ups - es sieht so aus, als hätte ich versucht, den Code zu ändern, um die @ + building_list loszuwerden (weil das ein Punkt der Verwirrung ist), aber ich habe ihn nicht überall verstanden. Danke für den Tipp! Nur das Ändern in @ + id sollte es beheben
Hamy

4

Ich hatte ein Problem mit der Filterung, die Ergebnisse wurden gefiltert, aber nicht wiederhergestellt !

Vor dem Filtern (Aktivitätsstart) habe ich eine Listensicherung erstellt. (Nur eine weitere Liste mit denselben Daten.)

Beim Filtern werden der Filter und der Listenadapter mit der Primärliste verbunden.

Der Filter selbst verwendete jedoch die Daten aus der gesicherten Liste.

Dies stellte in meinem Fall sicher, dass die Liste sofort aktualisiert wurde und selbst beim Löschen von Suchbegriffzeichen die Liste in jedem Fall erfolgreich wiederhergestellt wird :)

Trotzdem danke für diese Lösung.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.