web-dev-qa-db-fra.com

Filtre d'affichage de liste Android

J'ai créé une vue de liste dans Android et je souhaite ajouter un texte à modifier au-dessus de la liste. Lorsque l'utilisateur saisira du texte, la liste sera filtrée en fonction de la saisie de l'utilisateur.

quelqu'un peut-il me dire s'il existe un moyen de filtrer l'adaptateur de liste dans Android?

89

Ajoutez un EditText au dessus de votre liste dans son fichier de disposition .xml. Et dans votre activité/fragment ..

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 ici consiste à ajouter un OnTextChangeListener à votre texte édité et à l'intérieur de sa méthode de rappel, appliquez un filtre à l'adaptateur de votre liste.

EDIT

Pour obtenir un filtre sur votre adaptateur de base personnalisé, vous devez implémenter une interface filtrable.

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

À l'intérieur de performFiltering (), vous devez effectuer une comparaison réelle de la requête de recherche avec les valeurs de votre base de données. Il passera son résultat à la méthode publishResults ().

131
Puru Pawar

Implémentez votre adaptateur Filtrable:

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

puis créez votre classe de filtre:

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

}

ainsi, votre adaptateur est filtrable. Vous pouvez alors transférer l'élément de filtre au filtre de l'adaptateur et effectuer le travail. J'espère que cela vous sera utile.

9
M.Kouchi

Si le sujet vous intéresse toujours, je trouve que la meilleure approche pour filtrer des listes consiste à créer une classe de filtre générique et à l’utiliser avec certaines techniques de réflexion/génériques de base contenues dans le Java old package SDK de l’école Voici ce que j’ai fait:

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

Et ensuite, la seule chose à faire est de créer le filtre en tant que classe de membre (éventuellement dans "onCreate" de la vue) en transmettant votre référence d'adaptateur, votre liste et la méthode à appeler pour le filtrage:

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

La seule chose qui manque maintenant, est de remplacer la méthode "getFilter" dans la classe d'adaptateur:

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

Terminé! Vous devez filtrer votre liste avec succès - Bien entendu, vous devez également implémenter votre algorithme de filtrage de la meilleure façon qui décrit votre besoin, le code ci-dessous n’est qu’un exemple.. J'espère que ça vous a aidé, prenez soin de vous.

1
jbrios777