【问题标题】:RecyclerView filter not filteringRecyclerView 过滤器不过滤
【发布时间】:2023-04-05 14:04:02
【问题描述】:

我正在尝试在我的 RecyclerView 中实现搜索过滤器,就像在 this post 中一样

我已经对其进行了调试,它确实按预期过滤了项目,但应用程序中的列表似乎没有改变。 IE:我过滤了一个名字,有7个结果,在屏幕上是原始列表。

我的 onCreateMenuOptions 活动是:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);

    final MenuItem searchItem = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override public boolean onQueryTextSubmit(String filterString) {
            adapter.getFilter().filter(filterString);
            return true;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            return false;
        }
    });

    return true;
}

我的适配器如下所示:

public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder> implements INameableAdapter {
    private List<Anime> items;
    private List<Anime> filteredItems;
    private AnimeFilter animeFilter;

    final private Context context;

    @Override
    public Character getCharacterForElement(int element) {
        Character c = items.get(element).getTitle().charAt(0);
        if(Character.isDigit(c)){
            c = '#';
        }
        return c;
    }

    public static class AnimeViewHolder extends RecyclerView.ViewHolder {
        // Campos respectivos de un item
        final public ImageView img;
        final public TextView title;

        public AnimeViewHolder(View v) {
            super(v);
            img = (ImageView) v.findViewById(R.id.image);
            title = (TextView) v.findViewById(R.id.title);
        }
    }

    public AnimeAdapter(List<Anime> items, Context context) {
        this.items = items;
        this.context = context;
        this.filteredItems = new ArrayList<>();
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public AnimeViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.anime_card, viewGroup, false);
        return new AnimeViewHolder(v);
    }

    @Override
    public void onBindViewHolder(AnimeViewHolder viewHolder, int i) {
        if (BuildConfig.DEBUG) {
            //This is made to check if the image cache is working as expected.
            Picasso.with(context).setIndicatorsEnabled(true);
            Picasso.with(context).setLoggingEnabled(true);
        }
        final int position = i;
        final ImageView imageView = viewHolder.img;
        Picasso.with(context)
                .load(items.get(i).getImageUrl())
                .into(imageView);
        viewHolder.title.setText(items.get(i).getTitle());

        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Intent intent = new Intent(context, TabActivity.class);
                Bundle b = new Bundle();
                b.putString("title", items.get(position).title);
                b.putString("playlist", items.get(position).playlist);
                imageView.buildDrawingCache();
                Bitmap image = imageView.getDrawingCache();
                b.putParcelable("imageBitmap", image);
                intent.putExtras(b);

                v.getContext().startActivity(intent);
            }
        });
    }

    public Filter getFilter() {
        if(animeFilter == null)
            animeFilter = new AnimeFilter(this, items);
        return animeFilter;
    }

    private static class AnimeFilter extends Filter {

        private final AnimeAdapter adapter;

        private final List<Anime> originalList;

        private final List<Anime> filteredList;

        private AnimeFilter(AnimeAdapter adapter, List<Anime> originalList) {
            super();
            this.adapter = adapter;
            this.originalList = new LinkedList<>(originalList);
            this.filteredList = new ArrayList<>();
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            filteredList.clear();
            final FilterResults results = new FilterResults();

            if (constraint.length() == 0) {
                filteredList.addAll(originalList);
            } else {
                final String filterPattern = constraint.toString().toLowerCase().trim();

                for (final Anime anime : originalList) {
                    if (anime.getTitle().toLowerCase().contains(filterPattern)) {
                        filteredList.add(anime);
                    }
                }
            }
            results.values = filteredList;
            results.count = filteredList.size();
            return results;
        }

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

我在这里忘记了什么?

提前致谢!

【问题讨论】:

  • 你能把你的适配器的所有代码都放上去吗?
  • @ramineftekhari 完成,已编辑

标签: android android-recyclerview


【解决方案1】:

我对您的代码做了一些更改。

检查一下:

public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder> implements INameableAdapter {
private List<Anime> items;
private List<Anime> filteredItems;
private AnimeFilter animeFilter;

final private Context context;

@Override
public Character getCharacterForElement(int element) {
    Character c = items.get(element).getTitle().charAt(0);
    if(Character.isDigit(c)){
        c = '#';
    }
    return c;
}

public static class AnimeViewHolder extends RecyclerView.ViewHolder {
    // Campos respectivos de un item
    final public ImageView img;
    final public TextView title;

    public AnimeViewHolder(View v) {
        super(v);
        img = (ImageView) v.findViewById(R.id.image);
        title = (TextView) v.findViewById(R.id.title);
    }
}

public AnimeAdapter(List<Anime> items, Context context) {
    this.items = items;
    this.context = context;
    this.filteredItems = new ArrayList<>();
    // we copy the original list to the filter list and use it for setting row values
    this.filteredItems.addAll(items);
}

@Override
public int getItemCount() {
    return filteredItems.size();//you must always return count of filtered rows
}

@Override
public AnimeViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

    View v = LayoutInflater.from(viewGroup.getContext())
            .inflate(R.layout.anime_card, viewGroup, false);
    return new AnimeViewHolder(v);
}

@Override
public void onBindViewHolder(AnimeViewHolder viewHolder, int i) {
    if (BuildConfig.DEBUG) {
        //This is made to check if the image cache is working as expected.
        Picasso.with(context).setIndicatorsEnabled(true);
        Picasso.with(context).setLoggingEnabled(true);
    }
    final int position = i;
    final ImageView imageView = viewHolder.img;
    Picasso.with(context)
            .load(filteredItems.get(i).getImageUrl())//we you filteredItems instead of items
            .into(imageView);
    viewHolder.title.setText(filteredItems.get(i).getTitle());

    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View v) {
            Intent intent = new Intent(context, TabActivity.class);
            Bundle b = new Bundle();
            b.putString("title", filteredItems.get(position).title);
            b.putString("playlist", filteredItems.get(position).playlist);
            imageView.buildDrawingCache();
            Bitmap image = imageView.getDrawingCache();
            b.putParcelable("imageBitmap", image);
            intent.putExtras(b);

            v.getContext().startActivity(intent);
        }
    });
}

public Filter getFilter() {
    if(animeFilter == null)
        animeFilter = new AnimeFilter(this, items);
    return animeFilter;
}

private static class AnimeFilter extends Filter {

    private final AnimeAdapter adapter;

    private final List<Anime> originalList;

    private final List<Anime> filteredList;

    private AnimeFilter(AnimeAdapter adapter, List<Anime> originalList) {
        super();
        this.adapter = adapter;
        this.originalList = new LinkedList<>(originalList);
        this.filteredList = new ArrayList<>();
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        filteredList.clear();
        final FilterResults results = new FilterResults();

        if (constraint.length() == 0) {
            filteredList.addAll(originalList);
        } else {
            final String filterPattern = constraint.toString().toLowerCase().trim();

            for (final Anime anime : originalList) {
                if (anime.getTitle().toLowerCase().contains(filterPattern)) {
                    filteredList.add(anime);
                }
            }
        }
        results.values = filteredList;
        results.count = filteredList.size();
        return results;
    }

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

}

【讨论】:

  • 我复制你的代码并且: - 加载时,屏幕是黑色的。 - 过滤时,显示结果。 - 当我清除过滤器时,它会在开始时显示它应该显示的内容。我认为这与我活动中的项目负载有关。在我设置我的适配器之前,它会从互联网上抓取一个 XML 列表(new AnimeAdapter(items, this);)
  • 我将构造函数更改为: public AnimeAdapter(List items, Context context) { this.items = items; this.context = 上下文; //this.filteredItems = new ArrayList(); this.filteredItems = 项目; // 我们将原始列表复制到过滤器列表并使用它来设置行值 //this.filteredItems.addAll(items); ,它工作得很好。谢谢,我没想到今天会这样。你是最棒的!
【解决方案2】:

问题是您使用items 列表中的项目而不是filteredItems 填充您的RecyclerView。 在您的过滤器中,您只需更新filteredItems 列表并通知适配器发生了某些变化。但实际上适配器用来填充RecyclerView 的列表保持不变。

因此,将您的适配器更改为始终使用过滤后的列表。

【讨论】:

  • 感谢您的回答帮助我找到问题并追溯代码
猜你喜欢
  • 2021-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-23
相关资源
最近更新 更多