リストビューフィルターAndroid


92

私はandroidでリストビューを作成し、リストの上に編集テキストを追加します。ユーザーがテキストを入力すると、リストはユーザー入力に従ってフィルタリングされます

Androidでリストアダプタをフィルタリングする方法がある場合、誰か私に教えてもらえますか?


1
こんにちは、この例を試し例1と第二1 例2、私はこのtutorials..Iに基づいて、同じを実装しているが、これはあなたを助けることを願っています
Pragnani

5
上の答えは私に十分な情報を提供しませんでした。同様の質問に対するこの回答には、より多くのコンテキストがあり、私を整理するのに十分な情報でした。
James Skemp、2015

私は、フィルタレコードにしたいリサイクルビューを使用していますが、私は、カスタムキーパッドなどのテキスト編集に入力を与えるためにカスタムボタンを使用していますが、私はボタン速いクリックの遅延を取得し、あなたは私が何千ものレコードを持っているthis.Iから抜け出すのを助けることができます
Sagar

回答:


138

.xmlレイアウトファイルのリストビューの上にEditTextを追加します。そしてあなたの活動/フラグメントで..

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

ここでの基本は、OnTextChangeListenerを編集テキストに追加し、そのコールバックメソッド内でフィルターをリストビューのアダプターに適用することです。

編集する

カスタムBaseAdapterにフィルターを適用するには、Filterableインターフェースを実装する必要があります。

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

performFiltering()の内部では、検索クエリとデータベースの値を実際に比較する必要があります。結果をpublishResults()メソッドに 渡します。


BaseAdapterを拡張するカスタムアダプターを作成し、その中にリストに表示されるオブジェクトのベクターを定義しました。上記のコードを使用しようとすると、アダプターにgetFilterメソッドが見つからなかったため、インターフェイスを実装する必要があるかどうか教えてください??
Amira Elsayed Ismail 2013

BaseAdapterの場合のデータのフィルタリングは、少し注意が必要です。BaseAdapterの実装にFilterableインターフェイスを実装する必要があります。次に、getFilter()メソッドを使用し、その中に、使用する2つのコールバックメソッドを実装する必要があります。void publishResults()およびFilterResults performFiltering(CharSequence constraint)。
プルパワール、2013

簡単な例でサポートできますか?
Amira Elsayed Ismail 2013

はい。私の回答の編集セクションを確認してください。
プルパワール2013

1
これに関して、SOに別の質問を投稿することをお勧めします。同じ投稿にさまざまな質問を繰り返し続けるのは適切な方法ではないためです。さて、ヘッドアップとして、配列リスト全体を最初に別の一時的な配列リストにコピーし、onPerformFiltering()メソッド内でこの一時リストを検索に使用します。これはあなたの問題を解決します。そして、それがあなたを助けたならば、賛成票を投じるか、そして/または答えを受け入れてください。
プルパワール2013

9

フィルター可能なアダプターを実装します。

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

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

}

このようにして、アダプターはフィルター可能です。フィルター項目をアダプターのフィルターに渡して、作業を行うことができます。これがお役に立てば幸いです。


1

まだ誰もがこの話題に興味がある場合、リストをフィルタリングするための最良のアプローチは、汎用のFilterクラスを作成し、Javaの古い学校のSDKパッケージに含まれているいくつかの基本的なリフレクション/ジェネリック技術で使用することです。これが私がしたことです:

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

その後、行う必要があるのは、フィルターをメンバークラスとして(おそらくビューの "onCreate"内に)作成し、アダプター参照、リスト、およびフィルタリングのために呼び出すメソッドを渡すことだけです。

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

今欠けている唯一のものは、アダプタクラスの「getFilter」メソッドをオーバーライドすることです。

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

すべて完了!リストを正常にフィルタリングする必要があります- もちろん、必要に応じてフィルターアルゴリズムを最適な方法で実装する必要があります。以下のコードは単なる例です。。お役に立てば幸いです。


私はアンドロイドについては知りませんが、リソースを大量に消費するため、可能であればリフレクションを回避するように言われたことを覚えています(通常、Windowsモバイルアプリケーションで作業するため、これが問題になる可能性があります)、これはAndroidにも当てはまりますか?または、リフレクションはジェネリックなしで実際のクラスを構築するのと同じ効果がありますか?フィルター可能なテンプレートを作成し、パラメーターとして使用されるクラスとメソッドを追加することを考えていました
Cruces

はい、あなたは正しいです。ここでも同じことが当てはまります。リフレクションはプログラムの処理に重みを与えますが、この場合は非常に簡単に使用できます。ジェネリック/テンプレート表記で使用しているため、コンパイラーにも役立ちます。幸運を!
jbrios777

注意リフレクションを使用すると、難読化(dexguard / proguard)で問題が発生する場合があります。
Alexey、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.