【问题标题】:Filter in listview did not filter from the full list, but from already filtered list列表视图中的过滤器不是从完整列表中过滤,而是从已经过滤的列表中过滤
【发布时间】:2020-03-07 14:46:43
【问题描述】:

我有一个带有过滤器的列表视图。当我在用作过滤器的编辑文本中输入一些单词时,例如“david”,它运行良好,列表中的项目被过滤,它将显示所有包含“david”的项目。但是当我删除一些单词时,例如“dav”,列表仍然被过滤,但它是从最后一个被“david”过滤的。

假设我有 40 个项目,通过“david”过滤,变成 24 个项目。然后我用“dav”再次过滤它,它是从“24 项”一项中过滤出来的,而不是“40 项”一项。

这是我的自定义适配器:

public class WRegistrantListAdapter extends ArrayAdapter<Registrant> {

    private Context mContext;
    private int mResource;
    private List<Registrant> mOriginalList;
    private List<Registrant> mFilteredList;

    public WRegistrantListAdapter(Context context, int resource, ArrayList<Registrant> oobjects, int workshopItemId) {
        super(context, resource, oobjects);
        mContext = context;
        mResource = resource;
        mFilteredList = oobjects;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        //contains code for displaying item.
    }

    @NonNull
    @Override
    public Filter getFilter() {
        return new Filter() {

            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                FilterResults result = new FilterResults();
                String constraint = charSequence.toString().toLowerCase();

                if (mOriginalList == null) {
                    mOriginalList = mFilteredList;
                    Toast.makeText(mContext, String.valueOf(mOriginalList.size()), Toast.LENGTH_SHORT).show();
                }

                if (constraint == null || constraint.isEmpty() || constraint.equals("")) {
                    result.values = mOriginalList;
                    result.count = mOriginalList.size();
                } else {
                    List<Registrant> list = new ArrayList<>();
                    int max = mOriginalList.size();
                    for (int cont = 0; cont < max; cont++) {
                        Registrant item = mOriginalList.get(cont);
                        boolean contains =
                            item.getRegistrantName().toLowerCase().contains(constraint) ||
                                    item.getRegistrantNumber().toLowerCase().contains(constraint);
                        if (contains) {
                            list.add(mOriginalList.get(cont));
                        }
                    }
                    result.values = list;
                    result.count = list.size();
                }

                return result;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                clear();
                addAll((ArrayList<Registrant>) results.values);
                notifyDataSetChanged();
            }
        };
    }
}

过滤中的哪一部分是错误的?任何帮助将非常感激。希望我的解释不会令人困惑,因为英语不是我的母语。

【问题讨论】:

  • 尝试将mOriginalList = mFilteredList; 更改为mOriginalList = new ArrayList&lt;&gt;(mFilteredList);。希望有帮助!
  • 谢谢,它正在工作! mOriginalList = mFilteredList; 之间有何不同?和 mOriginalList = new ArrayList(mFilteredList);?你能把你的答案写出来让我接受吗?

标签: android android-listview android-filter


【解决方案1】:

您需要两个不同的列表进行过滤,所以尝试将mOriginalList = mFilteredList; 更改为mOriginalList = new ArrayList&lt;&gt;(mFilteredList); 可能会解决问题。

解释:

mOriginalList = mFilteredList; 是具有两个不同名称的同一个列表。它在模块化程序中很有帮助,就像适配器构造函数中的mFilteredList = oobjects;

mOriginalList = new ArrayList&lt;&gt;(mFilteredList);是对m​​FilteredList做一个shallow拷贝,存储为mOriginalList,所以列表不一样。

浅拷贝和深拷贝:

示例:如果您的自定义类 Registrant 包含名为 sample 的公共字段(列表、地图或自定义对象等,需要 new 来创建) .在浅拷贝下,mOriginalList = new ArrayList&lt;&gt;(mFilteredList);,mOriginalList.get(i) 是 mFilteredList.get(i) 的副本,它们是 2 个不同的 Registrant 对象。但是 mOriginalList.get(i).sample 和 mFilteredList.get(i).sample 是同一个对象。

如果需要 mOriginalList.get(i).sample 和 mFilteredList.get(i).sample 是不同的对象,则称为深拷贝。没有现成的方法可以进行深度复制,您必须根据您的自定义类制作自己的方法。但是到现在为止,我从来没有遇到过需要深拷贝的案例。

希望有帮助!

【讨论】:

    【解决方案2】:

    您应该在适配器中保留两个单独的列表,例如,

    private List<Registrant> mOriginalList = new ArrayList();
    private List<Registrant> mFilteredList = new ArrayList();
    
    public WRegistrantListAdapter(Context context, int resource, ArrayList<Registrant> oobjects, int workshopItemId) {
        super(context, resource, oobjects);
        mContext = context;
        mResource = resource;
        mFilteredList.addAll(oobjects);
        mOriginalList.addAll(oobjects);
    }
    

    最初,它们应该具有相同的值,您将使用过滤列表来显示您的数据。稍后在过滤器中,您应该发布您的数据,例如

    @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    filteredList.clear();
                    filteredList.addAll((ArrayList<Registrant>) results.values);
                    notifyDataSetChanged();
                }
    

    一个完整的例子可以在Filter ListView with arrayadapter找到

    【讨论】:

    • 我尝试了您的建议,但结果仍然相同。 mList 的大小发生了变化,尽管我没有对它做任何事情。
    • 我根据您提供的链接更新了代码库。我将 mList 更改为 mOriginalList 以使其更易于理解。但还是一样,mOriginalList的大小在不应该的地方改变了
    • 您将同一个对象分配给两个列表。您可以在构造函数中执行此操作。我已经更新了我的答案,希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-12-08
    • 2017-08-26
    • 2021-08-18
    • 2023-03-23
    • 2017-06-26
    • 1970-01-01
    • 2012-09-15
    • 2017-05-08
    相关资源
    最近更新 更多