【问题标题】:List view not returning to original state after clearing search清除搜索后列表视图未恢复到原始状态
【发布时间】:2015-06-22 16:32:21
【问题描述】:

每当我从搜索视图中取消搜索时,我都会尝试让我的列表再次显示我的所有项目,但由于某种奇怪的原因,列表只会卡在上一次搜索的结果中。有谁知道我的代码有什么问题以及如何解决这个问题?我认为过滤器相关代码有问题,但我不知道它是什么。

FilterListFragment.java

public class ItemListAdapter extends BaseAdapter implements Filterable {

    private List<Item> mData;
    private List<Item> mFilteredData;
    private LayoutInflater mInflater;
    private ItemFilter mFilter;

    public ItemListAdapter (List<Item> data, Context context) {
        mData = data;
        mFilteredData = data;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return mFilteredData.size();
    }

    @Override
    public String getItem(int position) {
        return mFilteredData.get(position).getItem();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder;
        if (convertView == null) {
           convertView = mInflater.inflate(R.layout.item_row, parent, false);
            holder = new ViewHolder();

            holder.title = (TextView) convertView.findViewById(R.id.item_title);
            holder.description = (TextView) convertView.findViewById(R.id.item_description);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.title.setText(mData.get(position).getItem());
        holder.description.setText(mData.get(position).getItemDescription());

        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ItemFilter();
        }
        return mFilter;
    }

    /**
     * View holder
     */
    static class ViewHolder {
        private TextView title;
        private TextView description;
    }

    /**
     * Filter for filtering list items
     */
    private class ItemFilter extends Filter {

        /**
         * Invoked on a background thread.  This is where all the filter logic should go
         * @param constraint the constraint to filter on
         * @return the resulting list after applying the constraint
         */
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (TextUtils.isEmpty(constraint)) {
                results.count = mData.size();
                results.values = mData;
            } else {
                //Create a new list to filter on
                List<Item> resultList = new ArrayList<Item>();
                for (Item str : mData) {
                    if (str.getItem().toLowerCase().contains(constraint.toString().toLowerCase())) {
                        resultList.add(str);
                    }
                }
                results.count = resultList.size();
                results.values = resultList;
            }
            return results;
        }

        /**
         * Runs on ui thread
         * @param constraint the constraint used for the result
         * @param results the results to display
         */
        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            if (results.count == 0) {
                notifyDataSetInvalidated();
            } else {
                mFilteredData = (ArrayList<Item>)results.values;
                notifyDataSetChanged();
            }
        }
    }
}

列表正常

处于过滤状态的列表

【问题讨论】:

    标签: java android xml android-activity android-listfragment


    【解决方案1】:

    您正在对原始数据而不是过滤后的数据进行操作。您应该保留对原始数据的引用,并将过滤后的数据用于所有其他目的。以便在清除搜索时显示原始数据。

    mData的所有用法替换为mFilteredData,如下所示,仅使用原始数据生成过滤后的数据:

    private List<String> mData;
    private List<String> mFilteredData;
    private LayoutInflater mInflater;
    private ItemFilter mFilter;
    
    public ItemListAdapter (List<String> data, Context context) {
        mData = data;
        mFilteredData = data;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    
    @Override
    public int getCount() {
        return mFilteredData.size();
    }
    
    @Override
    public String getItem(int position) {
        return mFilteredData.get(position);
    }
    
    @Override
    public long getItemId(int position) {
        return position;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    
        String strItem = mFilteredData.get(position);
        ViewHolder holder;
        if (convertView == null) {
           convertView = mInflater.inflate(R.layout.item_row, parent, false);
    
            holder = new ViewHolder();
            holder.mTvItem = (TextView) convertView.findViewById(R.id.tv_item);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
    
        holder.mTvItem.setText(strItem);
    
        return convertView;
    }
    
    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ItemFilter();
        }
        return mFilter;
    }
    
    /**
     * View holder
     */
    static class ViewHolder {
        private TextView mTvItem;
    }
    
    /**
     * Filter for filtering list items
     */
    private class ItemFilter extends Filter {
    
        /**
         * Invoked on a background thread.  This is where all the filter logic should go
         * @param constraint the constraint to filter on
         * @return the resulting list after applying the constraint
         */
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
    
            FilterResults results = new FilterResults();
    
            if (TextUtils.isEmpty(constraint)) {
                results.count = mData.size();
                results.values = mData;
            } else {
                //Create a new list to filter on
                List<String> resultList = new ArrayList<>();
                for (String str : mData) {
                    if (str.toLowerCase().contains(constraint.toString().toLowerCase())) {
                        resultList.add(str);
                    }
                }
                results.count = resultList.size();
                results.values = resultList;
            }
            return results;
        }
    
        /**
         * Runs on ui thread
         * @param constraint the constraint used for the result
         * @param results the results to display
         */
        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
    
            if (results.count == 0) {
                notifyDataSetInvalidated();
            } else {
                mFilteredData = (ArrayList<String>)results.values;
                notifyDataSetChanged();
            }
        }
    }
    

    【讨论】:

    • 只是为了澄清我的列表视图现在每个项目有 2 行而不是 1 行。该代码仍然有效吗?
    • 是的,如果您需要匹配第二个项目,只需添加 ||在performFiltering() 中进行比较以检查您的第二项时的条件。
    • 酷,但是由于某种原因我的列表没有正确过滤。例如当我输入“欧洲”时,带有欧洲标题的项目不会出现,而是非洲出现。我的 ItemListAdapter.java 已更新,您可以通过屏幕截图再次查看。
    • 您的过滤器代码看起来不错。你需要在你的getView()holder.title.setText(mData.get(position).getItem());holder.description.setText(mData.get(position).getItemDescription());中使用filtered data
    • 太棒了——谢谢。如我的屏幕截图所示,没有任何项目包含字母“x”。我只是想知道如果我输入的字母不在任何项目标题中,是否有可能使列表视图不可见并在屏幕中间显示“无结果”标签?
    【解决方案2】:

    在 onQueryTextChange() 中添加一条日志语句,以便您查看过滤器字符串的变化情况。请注意,当搜索视图关闭时,SearchView 不会使用空字符串调用 onQueryTextChange()。您需要决定何时清除搜索字符串,或许可以为此添加一个控件,然后自己进行清除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-09
      • 1970-01-01
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多