【问题标题】:List View Filter Android列表视图过滤器 Android
【发布时间】:2013-01-17 19:03:25
【问题描述】:

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

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

【问题讨论】:

  • 嗨试试这个例子Example one和第二个例子Example 2我已经根据这个教程实现了同样的..我希望这会对你有所帮助
  • 最佳答案只是没有为我提供足够的信息。 This answer 对一个类似的问题有更多的背景信息,并且正好有足够的信息让我理清思路。
  • 我正在使用回收站视图我想过滤记录,但我正在使用自定义按钮向自定义键盘等编辑文本提供输入,但我在按钮快速单击时出现延迟,你能帮我摆脱吗这。我有成千上万的记录

标签: android listview search filter android-listview


【解决方案1】:

在其 .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 的自定义适配器,并在其中定义了一个将显示在列表中的对象的 Vector,当我尝试使用上述代码时,我找不到 getFilter我的适配器中的方法,所以你能告诉我是否必须实现任何接口吗??
  • 在 BaseAdapter 的情况下过滤数据有点棘手。您必须为 BaseAdapter 的实现实现 Filterable 接口。然后您将拥有 getFilter() 方法,并且在其中您必须实现两个回调方法才能使用; void publishResults() 和 FilterResults performFiltering(CharSequence 约束)。
  • 你能举个简单的例子吗?
  • 是的。检查我答案的编辑部分。
  • 我建议您在 SO 上发布另一个关于此的问题。因为在同一个帖子中不断提出不同的问题不是正确的方法。好吧,作为提醒,只需首先将整个数组列表复制到另一个临时数组列表中,然后在 onPerformFiltering() 方法中使用这个临时列表进行搜索。这将解决您的问题。如果对您有帮助,请投票和/或接受答案。
【解决方案2】:

实现您的适配器 Filterable:

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

然后创建您的过滤器类:

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

}

这样,您的适配器是可过滤的,您可以将过滤器项传递给适配器的过滤器并完成工作。 我希望这会有所帮助。

【讨论】:

    【解决方案3】:

    如果有人仍然对这个主题感兴趣,我发现过滤列表的最佳方法是创建一个通用的 Filter 类,并将其与 Java old school 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;
    }
    

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

    【讨论】:

    • 我不了解 android,但我记得在 c# 中被告知尽量避免反射,因为它非常占用资源(我通常在 windows 移动应用程序上工作,所以这可能是一个问题),这适用于android吗?或者反射是否与构建没有泛型的实际类具有相同的效果?我正在考虑为可过滤创建一个模板,只需添加用作参数的类和方法
    • 是的,你是对的。这同样适用于此,反射赋予程序处理权重,但在这种情况下,它的使用非常简单,并且因为我们将它与通用/模板表示法一起使用,它也有助于编译器。祝你好运!
    • 注:如果你使用反射,你可能会遇到混淆(dexguard/proguard)的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    相关资源
    最近更新 更多