列表视图过滤器Android


93

我在android中创建了一个列表视图,我想在列表上方添加编辑文本,当用户输入文本时,该列表将根据用户输入进行过滤

谁能告诉我是否有办法在android中过滤列表适配器?


1
嗨,尝试一下本示例1和第二示例2我已经根据本教程实现了相同示例
。.

5
最佳答案只是没有为我提供足够的信息。这个类似问题的答案具有更多的上下文,并且正是足够的信息可以使我理清。
James Skemp 2015年

我正在使用“回收者视图”,我想过滤记录,但是我正在使用自定义按钮向诸如自定义键盘之类的编辑文本提供输入,但是我在按钮快速单击上遇到了延迟,您可以帮助我摆脱这个问题。我有成千上万的记录
萨加尔

Answers:


139

在列表视图顶部的.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添加到您的编辑文本中,并在其回调方法内部将过滤器应用于listview的适配器。

编辑

要对自定义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的自定义适配器,并在其中定义了将在列表中显示的对象的Vector,当我尝试使用上述代码时,我在Adapter中找不到getFilter方法,所以您可以请告诉我是否必须实现任何接口?
Amira Elsayed Ismail

在使用BaseAdapter的情况下过滤数据有些棘手。您将必须在BaseAdapter的实现中实现Filterable接口。然后,您将具有getFilter()方法,并且在其中必须实现两个回调方法才能使用;void publishResults()和FilterResults performFiltering(CharSequence约束)。
2013年

你能用一个简单的例子来支持吗?
Amira Elsayed Ismail

是。检查我的答案的编辑部分。
2013年

1
我建议您在SO上对此发布另一个问题。因为这不是将不同的问题不断发送到同一帖子中的正确方法。好了,首先,只需将整个arraylist复制到另一个临时arraylist中,然后在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;
}

然后,您唯一要做的就是将过滤器作为成员类(可能在View的“ onCreate”中)创建,并传递您的适配器引用,您的列表以及调用过滤的方法:

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

现在唯一缺少的是重写适配器类中的“ getFilter”方法:

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

全做完了!您应该成功过滤列表- 当然,您还应该以描述需求的最佳方式实现过滤算法,下面的代码只是一个例子。。希望能有所帮助,保重。


我不了解android,但是我记得被告知要尽量避免在c#中进行反射,因为这会占用大量资源(我通常在Windows Mobile应用程序上工作,因此可能会出现问题),这是否适用于android?还是反射与建立没有泛型的实际类具有相同的效果?我当时正在考虑创建一个可过滤的模板,并只是添加用作参数的类和方法
Cruces

是的,你是正确的。此处同样适用,反射对程序处理有重要作用,但是在这种情况下,它是一种非常简单的用法,并且由于我们将其与泛型/模板符号一起使用,因此它也有助于编译器。祝好运!
jbrios777 '16

注意:如果使用反射,则可能会混淆(dexguard / proguard)。
阿列克谢
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.