96 votes

List View Filter Android

J'ai créé une vue de liste dans Android et je veux ajouter du texte d'édition au-dessus de la liste et lorsque l'utilisateur entre 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 ?

1 votes

Bonjour, essayez cet exemple Premier exemple et le second Exemple 2 J'ai mis en œuvre la même chose sur la base de ce tutoriel. J'espère que cela vous aidera.

5 votes

La réponse du haut n'a pas fourni assez d'informations pour moi. Cette réponse à une question similaire a plus de contexte, et était exactement assez d'informations pour me permettre de m'en sortir.

0 votes

Je suis en train d'utiliser une vue de recyclage, je veux filtrer les enregistrements mais j'utilise des boutons personnalisés pour donner une entrée au texte d'édition comme un clavier personnalisé mais j'obtiens un retard sur le clic rapide du bouton, pouvez-vous m'aider à sortir de cela ?

144voto

Puru Pawar Points 1797

Oui. Ajoutez un EditText au-dessus de votre listview dans son fichier de mise en page aml. 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 est d'ajouter un OnTextChangeListener à votre texte d'édition et dans sa méthode de rappel, appliquez un filtre à l'adaptateur de votre liste.

EDIT

Pour obtenir un filtre vers votre BaseAdapter personnalisé, vous devrez implémenter Filtrable interface.

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 perfromFiltering() 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 à publishResults() méthode.

0 votes

J'ai créé un adaptateur personnalisé qui étend BaseAdapter et à l'intérieur duquel j'ai défini un vecteur de mon objet qui sera affiché dans la liste, lorsque j'essaie d'utiliser le code ci-dessus, je ne trouve pas la méthode getFilter dans mon adaptateur, alors pourriez-vous me dire si je dois implémenter une interface ?

0 votes

Le filtrage des données dans le cas de BaseAdapter est un peu plus délicat. Vous devrez implémenter l'interface Filterable dans votre implémentation de BaseAdapter. Vous aurez alors la méthode getFilter() et à l'intérieur de celle-ci vous devrez implémenter deux méthodes de rappel pour travailler avec ; void publishResults() et FilterResults performFiltering(CharSequence constraint).

0 votes

Pouvez-vous nous aider avec un exemple simple ?

9voto

M.Kouchi Points 41

Implémentez votre adaptateur Filterable :

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

}

De cette façon, votre adaptateur est filtrable, vous pouvez passer l'élément de filtre au filtre de l'adaptateur et faire le travail. J'espère que cela vous sera utile.

1voto

jbrios777 Points 181

Au cas où quelqu'un serait encore intéressé par ce sujet, je trouve que la meilleure approche pour filtrer des listes est de créer une classe Filter générique et de l'utiliser avec quelques techniques de base de réflexion/générique contenues dans le paquetage Java old school SDK. 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;
}

Ensuite, la seule chose à faire est de créer le filtre en tant que classe membre (éventuellement dans le "onCreate" de la vue) en passant la référence de votre 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, c'est de surcharger la méthode "getFilter" dans la classe de l'adaptateur :

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

Tout est fait ! Vous devriez réussir à filtrer votre liste - Bien sûr, vous devez également mettre en œuvre votre algorithme de filtrage de la meilleure façon possible pour répondre à vos besoins. Le code ci-dessous n'est qu'un exemple. . J'espère que cela vous a aidé, prenez soin de vous.

0 votes

Je ne sais pas ce qu'il en est pour Android, mais je me souviens qu'on m'a dit d'essayer d'éviter la réflexion si possible en C# parce qu'elle est assez gourmande en ressources (je travaille habituellement sur des applications mobiles Windows donc cela pourrait être un problème), est-ce que cela s'applique à Android ? ou est-ce que la réflexion a le même effet que de construire une classe réelle sans génériques ? Je pensais créer un modèle pour filterable et juste ajouter la classe et la méthode utilisée comme paramètres.

0 votes

Oui, vous avez raison. La même chose s'applique ici, la réflexion donne un poids au traitement du programme, mais dans ce cas, il s'agit d'une utilisation très simple, et parce que nous l'utilisons avec une notation générique/de modèle, cela aide également le compilateur. Bonne chance !

0 votes

N.B. Vous pouvez avoir des problèmes avec l'obfuscation (dexguard/proguard) si vous utilisez la réflexion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X