Filtro visualizzazione elenco Android


94

Ho creato una visualizzazione elenco in Android e voglio aggiungere testo di modifica sopra l'elenco e quando l'utente inserisce il testo l'elenco verrà filtrato in base all'input dell'utente

qualcuno può dirmi per favore se c'è un modo per filtrare l'adattatore dell'elenco in Android?


1
Ciao prova questo esempio Esempio uno e il secondo Esempio 2 Ho implementato lo stesso sulla base di questo tutorial
..

5
La risposta migliore non ha fornito informazioni sufficienti per me. Questa risposta a una domanda simile ha più contesto ed era esattamente informazioni sufficienti per farmi capire.
James Skemp

Sto usando la visualizzazione Recycler Voglio filtrare i record ma sto usando i pulsanti personalizzati per dare input al testo di modifica come la tastiera personalizzata, ma ho un ritardo sul clic veloce del pulsante puoi aiutarmi a uscire da questo.Ho record in migliaia
Sagar

Risposte:


141

Aggiungi un EditText in cima alla visualizzazione elenco nel suo file di layout .xml. E nella tua attività / frammento ..

lv = (ListView) findViewById(R.id.list_view);
    inputSearch = (EditText) findViewById(R.id.inputSearch);

// Adding items to listview
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name,    products);
lv.setAdapter(adapter);       
inputSearch.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        // When user changed the Text
        MainActivity.this.adapter.getFilter().filter(cs);
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }

    @Override
    public void afterTextChanged(Editable arg0) {}
});

La base qui è aggiungere un OnTextChangeListener al tuo testo di modifica e all'interno del suo metodo di callback applicare il filtro all'adattatore del tuo listview.

MODIFICARE

Per ottenere un filtro per il tuo BaseAdapter personalizzato, dovrai implementare l' interfaccia Filtrabile .

class CustomAdapter extends BaseAdapter implements Filterable {

    public View getView(){
    ...
    }
    public Integer getCount()
    {
    ...
    }

    @Override
    public Filter getFilter() {

        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

                arrayListNames = (List<String>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                FilterResults results = new FilterResults();
                ArrayList<String> FilteredArrayNames = new ArrayList<String>();

                // perform your search here using the searchConstraint String.

                constraint = constraint.toString().toLowerCase();
                for (int i = 0; i < mDatabaseOfNames.size(); i++) {
                    String dataNames = mDatabaseOfNames.get(i);
                    if (dataNames.toLowerCase().startsWith(constraint.toString()))  {
                        FilteredArrayNames.add(dataNames);
                    }
                }

                results.count = FilteredArrayNames.size();
                results.values = FilteredArrayNames;
                Log.e("VALUES", results.values.toString());

                return results;
            }
        };

        return filter;
    }
}

All'interno di performFiltering () è necessario eseguire il confronto effettivo della query di ricerca con i valori nel database. Passerà il risultato al metodo publishResults () .


Ho creato un adattatore personalizzato che estende BaseAdapter e al suo interno ho definito un Vector del mio oggetto che verrà mostrato nell'elenco, quando provo ad utilizzare il codice sopra non sono riuscito a trovare il metodo getFilter nel mio Adapter, quindi potresti per favore dimmi se devo implementare qualche interfaccia ??
Amira Elsayed Ismail

Filtrare i dati in caso di BaseAdapter è un po 'complicato. Dovrai implementare l'interfaccia Filtrabile nella tua implementazione di BaseAdapter. Avrai quindi il metodo getFilter () e al suo interno dovrai implementare due metodi di callback con cui lavorare; void publishResults () e FilterResults performFiltering (vincolo CharSequence).
Purush Pawar

puoi supportare con un semplice esempio per favore?
Amira Elsayed Ismail

Sì. Controlla la sezione MODIFICA della mia risposta.
Purush Pawar

1
Ti suggerisco di pubblicare un'altra domanda su SO riguardo a questo. Perché non è un modo corretto per continuare a porre domande diverse nello stesso post. Bene, come avvertimento, copia prima l'intero elenco di array in un altro elenco di array temporaneo e all'interno del metodo onPerformFiltering () usa questo elenco temporaneo per la ricerca. Questo risolverà il tuo problema. E per favore vota e / o accetta la risposta se ti è stata d'aiuto.
Purush Pawar

9

Implementa il tuo adattatore Filtrabile:

public class vJournalAdapter extends ArrayAdapter<JournalModel> implements Filterable{
private ArrayList<JournalModel> items;
private Context mContext;
....

quindi crea la tua classe Filter:

private class JournalFilter extends Filter{

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults result = new FilterResults();
        List<JournalModel> allJournals = getAllJournals();
        if(constraint == null || constraint.length() == 0){

            result.values = allJournals;
            result.count = allJournals.size();
        }else{
            ArrayList<JournalModel> filteredList = new ArrayList<JournalModel>();
            for(JournalModel j: allJournals){
                if(j.source.title.contains(constraint))
                    filteredList.add(j);
            }
            result.values = filteredList;
            result.count = filteredList.size();
        }

        return result;
    }
    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results.count == 0) {
            notifyDataSetInvalidated();
        } else {
            items = (ArrayList<JournalModel>) results.values;
            notifyDataSetChanged();
        }
    }

}

in questo modo, il tuo adattatore è Filtrabile, puoi passare l'elemento del filtro al filtro dell'adattatore e fare il lavoro. Spero che questo sia utile.


1

Nel caso qualcuno sia ancora interessato a questo argomento, trovo che l'approccio migliore per filtrare gli elenchi sia creare una classe Filter generica e usarla con alcune tecniche di riflessione / generics di base contenute nel pacchetto SDK della vecchia scuola Java. Ecco cosa ho fatto:

public class GenericListFilter<T> extends Filter {

    /**
     * Copycat constructor
     * @param list  the original list to be used
     */
    public GenericListFilter (List<T> list, String reflectMethodName, ArrayAdapter<T> adapter) {
        super ();

        mInternalList = new ArrayList<>(list);
        mAdapterUsed  = adapter;

        try {
            ParameterizedType stringListType = (ParameterizedType)
                    getClass().getField("mInternalList").getGenericType();
            mCompairMethod =
                    stringListType.getActualTypeArguments()[0].getClass().getMethod(reflectMethodName);
        }
        catch (Exception ex) {
            Log.w("GenericListFilter", ex.getMessage(), ex);

            try {
                if (mInternalList.size() > 0) {
                    T type = mInternalList.get(0);
                    mCompairMethod = type.getClass().getMethod(reflectMethodName);
                }
            }
            catch (Exception e) {
                Log.e("GenericListFilter", e.getMessage(), e);
            }

        }
    }

    /**
     * Let's filter the data with the given constraint
     * @param constraint
     * @return
     */
    @Override protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        List<T> filteredContents = new ArrayList<>();

        if ( constraint.length() > 0 ) {
            try {
                for (T obj : mInternalList) {
                    String result = (String) mCompairMethod.invoke(obj);
                    if (result.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
                        filteredContents.add(obj);
                    }
                }
            }
            catch (Exception ex) {
                Log.e("GenericListFilter", ex.getMessage(), ex);
            }
        }
        else {
            filteredContents.addAll(mInternalList);
        }

        results.values = filteredContents;
        results.count  = filteredContents.size();
        return results;
    }

    /**
     * Publish the filtering adapter list
     * @param constraint
     * @param results
     */
    @Override protected void publishResults(CharSequence constraint, FilterResults results) {
        mAdapterUsed.clear();
        mAdapterUsed.addAll((List<T>) results.values);

        if ( results.count == 0 ) {
            mAdapterUsed.notifyDataSetInvalidated();
        }
        else {
            mAdapterUsed.notifyDataSetChanged();
        }
    }

    // class properties
    private ArrayAdapter<T> mAdapterUsed;
    private List<T> mInternalList;
    private Method  mCompairMethod;
}

E in seguito, l'unica cosa che devi fare è creare il filtro come classe membro (possibilmente all'interno di "onCreate" della vista) passando il tuo riferimento all'adattatore, il tuo elenco e il metodo da chiamare per il filtro:

this.mFilter = new GenericFilter<MyObjectBean> (list, "getName", adapter);

L'unica cosa che manca ora è sovrascrivere il metodo "getFilter" nella classe dell'adattatore:

@Override public Filter getFilter () {
     return MyViewClass.this.mFilter;
}

Tutto fatto! Dovresti filtrare correttamente il tuo elenco - Ovviamente, dovresti anche implementare il tuo algoritmo di filtro nel modo migliore che descrive le tue necessità, il codice qui sotto è solo un esempio. . Spero sia stato d'aiuto, abbi cura di te.


Non so Android, ma ricordo che mi è stato detto di cercare di evitare la riflessione se possibile in c # perché richiede molte risorse (di solito lavoro su applicazioni Windows Mobile, quindi questo potrebbe essere un problema), questo vale per Android? o la riflessione ha lo stesso effetto che costruire una vera classe senza farmaci generici? Stavo pensando di creare un modello per filtrabili e aggiungere semplicemente la classe e il metodo utilizzati come parametri
Cruces

Sì, hai ragione. Lo stesso vale qui, la riflessione dà un peso all'elaborazione del programma, ma in questo caso è un suo uso molto semplice, e poiché lo stiamo usando con una notazione generica / modello, aiuta anche il compilatore. In bocca al lupo!
jbrios777

NB Potresti avere problemi con l'offuscamento (dexguard / proguard) se usi la reflection.
Alexey
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.