Come aggiornare dinamicamente un ListView su Android [chiuso]


159

Su Android, come posso ListViewfiltrare in base all'input dell'utente, dove gli elementi mostrati vengono aggiornati dinamicamente in base al TextViewvalore?

Sto cercando qualcosa del genere:

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

7
Nomino per la riapertura. Ho aggiornato il testo per renderlo più una domanda, ed è chiaramente una risorsa preziosa per la comunità dato che le risposte stanno ancora arrivando
Hamy,

Si prega di riaprire la domanda. È chiaramente utile.
SilenziosoNon

Risposte:


286

Innanzitutto, è necessario creare un layout XML che abbia sia EditText sia ListView.

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

Questo sistemerà tutto correttamente, con un bel EditText sopra ListView. Successivamente, crea un ListActivity come faresti normalmente, ma aggiungi una setContentView()chiamata nel onCreate()metodo in modo da utilizzare il nostro layout dichiarato di recente. Ricorda che abbiamo identificato il ListViewappositamente, con android:id="@android:id/list". Ciò consente ListActivitydi sapere quale ListViewvogliamo utilizzare nel nostro layout dichiarato.

    @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());
    }

L'esecuzione dell'app ora dovrebbe mostrare il tuo precedente ListView, con una bella casella sopra. Per fare in modo che quel riquadro faccia qualcosa, dobbiamo prendere l'input da esso e fare in modo che quell'input filtri l'elenco. Mentre molte persone hanno provato a farlo manualmente, la maggior parte delle ListView Adapter classi include un Filteroggetto che può essere utilizzato per eseguire il filtraggio automagicamente. Dobbiamo solo reindirizzare l'input da EditTextin a Filter. Si scopre che è abbastanza facile. Per eseguire un test rapido, aggiungi questa linea alla onCreate()chiamata

adapter.getFilter().filter(s);

Si noti che sarà necessario salvare il tuo ListAdapterin una variabile per far funzionare questo - ho salvato il mio ArrayAdapter<String>da prima in una variabile chiamata 'adattatore'.

Il prossimo passo è ottenere l'input dal EditText. Questo in realtà richiede un po 'di pensiero. Potresti aggiungere un OnKeyListener()al tuo EditText. Tuttavia, questo listener riceve solo alcuni eventi chiave . Ad esempio, se un utente inserisce "wyw", il testo predittivo probabilmente consiglierà "occhio". Fino a quando l'utente non sceglie "wyw" o "eye", OnKeyListenernon riceverai un evento chiave. Alcuni potrebbero preferire questa soluzione, ma l'ho trovata frustrante. Volevo ogni evento chiave, quindi ho potuto scegliere di filtrare o non filtrare. La soluzione è a TextWatcher. Basta creare e aggiungere un TextWatcheral EditTexte passare la ListAdapter Filterrichiesta di un filtro ogni volta che il testo cambia. Ricorda di rimuovere TextWatcherin OnDestroy()! Ecco la soluzione finale:

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
Esiste un modo semplice per filtrare ListView in "contiene" anziché "inizia con" la moda come fa questa soluzione?
Viktor Brešan,

12
Viktor - Se le parole che ti interessano sono separate da spazi, lo farà automaticamente. Altrimenti, non proprio. Probabilmente il modo più semplice sarebbe sottoclassare l'adapter estendendolo e sovrascrivere il metodo getFilter per restituire un oggetto Filter definito. Vedi github.com/android/platform_frameworks_base/blob/master/core/… per capire come funziona ArrayFilter predefinito - sarebbe semplice copiare il 95% di questo codice e cambiare le righe 479 e 486
Hamy

2
Hamy, eccellente riscrittura! Ho una domanda però: ho implementato questo e dopo ogni lettera che scrivo, ListView scompare per un paio di secondi e poi ritorna, filtrato. L'hai sperimentato? La mia intuizione è che è perché ho più di 600 elementi nell'elenco, con funzioni toString () non banali.
lowellk,

2
In modalità orizzontale su uno schermo più piccolo, la tastiera EditText + occupa l'intero schermo e ListView non è visibile! Qualche soluzione?
Martin Konicek,

4
È davvero necessario? > Ricorda di rimuovere TextWatcher in OnDestroy ()
Jojo il

10

l'esecuzione del programma provoca una chiusura forzata.

Ho scambiato la linea:

Android: id = "@ + building_list / search_box"

con

Android: id = "@ + id / search_box"

potrebbe essere questo il problema? A cosa serve la "@ + building_list"?


Johe, quando dici R.id.qualcosa, qualcosa esiste in id perché hai detto android: id = "@ + id / search_box". Se dici android: id = "@ + building_list / search_box", nel codice puoi chiamare findViewById (R.building_list.search_box); Qual è l'eccezione di livello superiore che stai ricevendo? Questo codice viene copiato senza compilare il test, quindi probabilmente ho lasciato almeno un errore lì da qualche parte
Hamy

Ciao Hamy, hai fatto riferimento a "@ + building_list / search_box" nel codice con "filterText = (EditText) findViewById (R.id.search_box);" Ecco perché mi chiedevo.
j7nn7k,

1
Forcleclose occorrs quando si inizia a digitare. Parte dell'errore: ERROR / AndroidRuntime (188): java.lang.NullPointerException 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): su xxx.com.ListFilter $ 1. onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): su android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERRORE / AndroidRuntime (188): su android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): su android.widget.TextView $ ChangeWatcher.onTextChanged (TextView.java : 6286)
j7nn7k, l'

Johe, Oops - sembra che stavo cercando di modificare il codice per sbarazzarmi di @ + building_list (perché è un punto di confusione) ma non l'ho preso dappertutto. Grazie per il consiglio! Basta cambiarlo in @ + id per risolverlo
Hamy,

4

ho avuto un problema con il filtro, che i risultati sono stati filtrati, ma non ripristinati !

quindi prima del filtraggio (inizio attività) ho creato un backup dell'elenco .. (solo un altro elenco, contenente gli stessi dati)

sul filtro, il filtro e il listadapter sono collegati all'elenco principale.

ma il filtro stesso ha utilizzato i dati dall'elenco di backup.

questo ha assicurato nel mio caso che l'elenco è stato aggiornato immediatamente e anche eliminando i caratteri di ricerca, l'elenco viene ripristinato con successo in ogni caso :)

grazie comunque per questa soluzione.

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.