2013-02-02 18 views
78

Ho creato una visualizzazione elenco in Android e voglio aggiungere modificare il testo sopra l'elenco e quando l'utente inserire il testo l'elenco verrà filtrato in base all'input dell'utenteelenco Visualizza Filtro Android

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

+1

Ciao prova questo esempio [Esempio uno] (https://rakhi577.wordpress.com/2012/06/26/buttons-on-list-view-with-easy-searching-in-android/) e il secondo uno [Esempio 2] (http://stackoverflow.com/questions/2463777/autocompletetextview-with-custom-list-how-to-set-up-onitemclicklistener) Ho implementato lo stesso basato su questo tutorial ... Spero che questo ti aiuterà – Pragnani

+0

+1 l masr ..... –

+4

La risposta migliore non ha fornito abbastanza informazioni per me. [Questa risposta] (http://stackoverflow.com/a/24771174/11912) a una domanda simile ha più contesto ed è stata esattamente abbastanza informazioni da farmi risolvere. –

risposta

122

Sì. Aggiungi un EditText in cima alla tua listview nel suo file di layout aml. E nella vostra 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 è di aggiungere un OnTextChangeListener per la modifica del testo e all'interno del suo metodo di callback Applica filtro per l'adattatore del ListView.

EDIT

Per arrivare filtro per la vostra abitudine BaseAdapter voi "ll necessario implementare filtrabili interfaccia.

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 perfromFiltering() devi fare effettivo confronto della cerca la query con i valori nel tuo database e passerà il suo risultato al metodo publishResults().

+0

Ho creato un adattatore personalizzato che estende BaseAdapter e al suo interno ho definito un vettore del mio oggetto che verrà mostrato nella lista, quando provo ad usare il codice precedente non sono riuscito a trovare il metodo getFilter nel mio adapter, quindi potrei per favore dimmi se devo implementare qualsiasi interfaccia ?? –

+0

Il filtraggio dei dati in caso di BaseAdapter è un po 'complicato. Dovrai implementare l'interfaccia Filterable per l'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). –

+0

puoi sostenere con un semplice esempio per favore? –

9

Implementare l'adattatore filtrabili:

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

quindi creare la 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, la scheda è filtrabili, è possibile passare elemento filtro per il filtro dell'adattatore e fare il lavoro. Spero che questo sia utile.

1

Nel caso in cui qualcuno sia ancora interessato a questo argomento, trovo che l'approccio migliore per gli elenchi di filtri sia quello di creare una classe Filter generica e utilizzarla con alcune tecniche di riflessione/generiche di base contenute nel pacchetto Java old school SDK. Ecco quello che 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 dopo, l'unica cosa che devi fare è quello di creare il filtro come classe membro (possibilmente entro il View "onCreate") passando il vostro riferimento adattatore, la vostra lista, e la il metodo da chiamare per il filtraggio:

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

l'unica cosa che manca ora, è quello di eseguire l'override del metodo "getFilter" nella classe di adattatori:

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

tutto fatto! Dovresti filtrare correttamente il tuo elenco - Naturalmente, dovresti anche implementare l'algoritmo del filtro nel modo migliore che descriva le tue necessità, il codice qui sotto è solo un esempio.. Spero che abbia aiutato, stammi bene.

+0

Non so Android, ma ricordo che mi è stato detto di provare a evitare la riflessione, se possibile, in C# perché è piuttosto dispendioso in termini di 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 di costruire una vera classe senza generici? Stavo pensando di creare un modello per filtrabile e aggiungendo semplicemente la classe e il metodo usato come parametri – Cruces

+0

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