Listenansicht Filter Android

92

Ich habe eine Listenansicht in Android erstellt und möchte Bearbeitungstext über der Liste hinzufügen. Wenn der Benutzer Text eingibt, wird die Liste nach Benutzereingaben gefiltert

Kann mir jemand bitte sagen, ob es eine Möglichkeit gibt, den Listenadapter in Android zu filtern?

Amira Elsayed Ismail
quelle
1
Hallo versuchen Sie dieses Beispiel Beispiel eins und das zweite Beispiel 2 Ich habe das gleiche basierend auf diesen Tutorials implementiert. Ich hoffe, dies wird Ihnen helfen
Pragnani
5
Die Top-Antwort lieferte mir einfach nicht genug Informationen. Diese Antwort auf eine ähnliche Frage hat mehr Kontext und war genau genug Information, um mich zu sortieren.
James Skemp
Ich verwende Recycler Ansicht ich Filter Aufzeichnungen wollen , aber ich bin mit-Buttons Eingang zum Bearbeiten von Text wie benutzerdefinierte Tastatur zu geben , aber ich Verzögerung immer schnell auf die Schaltfläche klicken , können Sie mir helfen , aus this.I haben Rekord in Tausend raus
Sagar

Antworten:

138

Fügen Sie einen EditText über Ihrer Listenansicht in die XML-Layoutdatei ein. Und in Ihrer Aktivität / 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) {}
});

Grundsätzlich müssen Sie Ihrem Bearbeitungstext einen OnTextChangeListener hinzufügen und innerhalb seiner Rückrufmethode den Filter auf den Adapter Ihrer Listenansicht anwenden.

BEARBEITEN

Um Filter zu Ihrer benutzerdefinierten BaseAdapter Sie "ll Notwendigkeit zu implementieren Filterbare Schnittstelle.

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

In performFiltering () müssen Sie die Suchabfrage tatsächlich mit Werten in Ihrer Datenbank vergleichen. Das Ergebnis wird an die Methode publishResults () übergeben .

Puru Pawar
quelle
Ich habe einen benutzerdefinierten Adapter erstellt, der BaseAdapter erweitert, und darin einen Vektor meines Objekts definiert, der in der Liste angezeigt wird. Wenn ich versuche, den obigen Code zu verwenden, konnte ich die getFilter-Methode in meinem Adapter nicht finden Bitte sagen Sie mir, ob ich eine Schnittstelle implementieren muss?
Amira Elsayed Ismail
Das Filtern der Daten bei BaseAdapter ist etwas schwierig. Sie müssen eine filterbare Schnittstelle für Ihre Implementierung von BaseAdapter implementieren. Sie haben dann die Methode getFilter () und müssen darin zwei Rückrufmethoden implementieren, mit denen Sie arbeiten können. void PublishResults () und FilterResults performFiltering (CharSequence-Einschränkung).
Puru Pawar
Können Sie bitte mit einem einfachen Beispiel unterstützen?
Amira Elsayed Ismail
Ja. Überprüfen Sie den Abschnitt BEARBEITEN meiner Antwort.
Puru Pawar
1
Ich schlage vor, dass Sie diesbezüglich eine weitere Frage zu SO stellen. Weil es nicht richtig ist, immer wieder verschiedene Fragen in einem Beitrag zu stellen. Kopieren Sie als Heads-Up zuerst die gesamte Arrayliste in eine andere temporäre Arrayliste und verwenden Sie diese temporäre Liste für die Suche in der onPerformFiltering () -Methode. Dies wird Ihr Problem lösen. Und bitte stimmen Sie zu und / oder akzeptieren Sie die Antwort, wenn es Ihnen geholfen hat.
Puru Pawar
9

Implementieren Sie Ihren Adapter Filterbar:

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

Erstellen Sie dann Ihre Filterklasse:

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

}

Auf diese Weise ist Ihr Adapter filterbar. Sie können Filterelemente an den Filter des Adapters übergeben und die Arbeit erledigen. Ich hoffe das wird hilfreich sein.

M. Kouchi
quelle
1

Falls sich noch jemand für dieses Thema interessiert, finde ich, dass der beste Ansatz zum Filtern von Listen darin besteht, eine generische Filterklasse zu erstellen und diese mit einigen Basisreflexions- / Generika-Techniken zu verwenden, die im Java Old School SDK-Paket enthalten sind. Folgendes habe ich getan:

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

Anschließend müssen Sie den Filter nur noch als Elementklasse erstellen (möglicherweise innerhalb des "onCreate" der Ansicht) und dabei Ihre Adapterreferenz, Ihre Liste und die zum Filtern aufzurufende Methode übergeben:

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

Jetzt fehlt nur noch das Überschreiben der Methode "getFilter" in der Adapterklasse:

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

Alles erledigt! Sie sollten Ihre Liste erfolgreich filtern - Natürlich sollten Sie Ihren Filteralgorithmus auch so implementieren, dass er Ihre Anforderungen am besten beschreibt. Der folgende Code ist nur ein Beispiel. . Hoffe es hat geholfen, pass auf dich auf.

jbrios777
quelle
Ich weiß nichts über Android, aber ich erinnere mich, dass mir gesagt wurde, ich solle versuchen, Reflexionen in c # möglichst zu vermeiden, da dies sehr ressourcenintensiv ist (ich arbeite normalerweise an Windows Mobile-Anwendungen, daher könnte dies ein Problem sein). Gilt dies für Android? oder hat Reflexion den gleichen Effekt wie der Aufbau einer tatsächlichen Klasse ohne Generika? Ich dachte daran, eine Vorlage zum Filtern zu erstellen und nur die Klasse und Methode hinzuzufügen, die als Parameter verwendet werden
Cruces
Ja, du hast recht. Gleiches gilt hier, Reflexion gibt der Programmverarbeitung ein Gewicht, aber in diesem Fall ist es eine sehr einfache Verwendung, und da wir es mit einer generischen / Template-Notation verwenden, hilft es auch dem Compiler. Viel Glück!
jbrios777
NB Sie können Probleme mit der Verschleierung (Dexguard / Proguard) haben, wenn Sie Reflexion verwenden.
Alexey