简体   繁体   English

使用字符串过滤嵌套 RecyclerView 中的项目

[英]Filter items in a nested RecyclerView using a String

To preface - my goal is to be able to search for an item in a NestedRecyclerView using a field.作为序言 - 我的目标是能够使用字段在 NestedRecyclerView 中搜索项目。

In my app, I have a HomeFragment.在我的应用程序中,我有一个 HomeFragment。 In said fragment, I have a recycler view(parent recyclerview), which, in turn, holds a RecyclerView(further - child or nested recyclerView).在所述片段中,我有一个回收器视图(父 recyclerview),它又包含一个 RecyclerView(进一步 - 子或嵌套的 recyclerView)。 Here are the adapters for both the parent and child recyclerviews respectively.这里分别是父和子 recyclerviews 的适配器。

public class HomeFragmentRvParentAdapter extends RecyclerView.Adapter<HomeFragmentRvParentAdapter.ParentRvViewHolder> {
    private Context context;
    private Map<String, ArrayList<Product>> products;
    private FragmentChangeCallback fragmentChangeCallback;
    ArrayList<String> categories;
    public HomeFragmentRvParentAdapter(Context context, Map<String, ArrayList<Product>> products, FragmentChangeCallback callback){
        this.context = context;
        this.fragmentChangeCallback = callback;
        this.products = products;
    }

    @NonNull
    @Override
    public ParentRvViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_fragment_recyclerview_item_parent, parent, false);
        categories = new ArrayList<>(products.keySet());
        return new ParentRvViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ParentRvViewHolder holder, int position) {
        holder.itemCategoryName.setText(categories.get(position));
        setChildAdapter(holder.itemChildRecyclerView, products.get(categories.get(position)));
    }

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

    public class ParentRvViewHolder extends RecyclerView.ViewHolder {
        TextView itemCategoryName;
        RecyclerView itemChildRecyclerView;
        public ParentRvViewHolder(@NonNull View itemView) {
            super(itemView);
            itemCategoryName = itemView.findViewById(R.id.category_name);
            itemChildRecyclerView = itemView.findViewById(R.id.child_recycler);
        }
    }
private void setChildAdapter(RecyclerView recyclerView, ArrayList<Product> products){
        HomeFragmentRvChildAdapter adapter = new HomeFragmentRvChildAdapter(context ,products, fragmentChangeCallback);
        recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
        recyclerView.setAdapter(adapter);

    }
}
public class HomeFragmentRvChildAdapter extends RecyclerView.Adapter<HomeFragmentRvChildAdapter.ChildViewHolder> {
    ArrayList<Product> products;
    Context context;
    FragmentChangeCallback fragmentChangeCallback;
    public HomeFragmentRvChildAdapter(Context context, ArrayList<Product>products, FragmentChangeCallback callback){
        this.products = products;
        this.context = context;
        this.fragmentChangeCallback = callback;
    }

    @NonNull
    @Override
    public ChildViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_fragment_recyclerview_item_child, parent, false);
        return new ChildViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ChildViewHolder holder, int position) {
        Glide.with(context).load(products.get(position).getIcon()).into(holder.iconView);
        holder.name.setText(products.get(position).getName());
        holder.description.setText(products.get(position).getDescription());
        holder.itemView.setOnClickListener(view -> {
            fragmentChangeCallback.fragmentChange(products.get(position).getPackageName());
        });
    }

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

    public class ChildViewHolder extends RecyclerView.ViewHolder {
        public ImageView iconView;
        public TextView name;
        public TextView description;
        public CardView cardView;
        public ChildViewHolder(@NonNull View itemView) {
            super(itemView);
            cardView = itemView.findViewById(R.id.cardView);
            iconView = itemView.findViewById(R.id.hf_item_icon_image);
            name = itemView.findViewById(R.id.app_title);
            description = itemView.findViewById(R.id.app_description);
        }
    }
}

public class Product{
    private String name;
    private String icon;
    private String category;
    private String description;
}

^fields of the Product class I use to fill the child recycler. ^ 产品 class 的字段我用来填充子回收器。

The way I pass data into this is - in my HomeFragmentViewModel, I get the data.我向其中传递数据的方式是 - 在我的 HomeFragmentViewModel 中,我获取数据。 I then categorize that data into a HashMap<String, ArrayList>, where the key is the category.然后我将该数据分类到 HashMap<String, ArrayList> 中,其中键是类别。 I then pass said map to my ParentRecyclerViewAdapter, which sets the category_title to the value of the key, and passes the linked ArrayList to the ChildRecyclerViewAdapter, that then divides all of it to display.然后我将所说的 map 传递给我的 ParentRecyclerViewAdapter,它将 category_title 设置为键的值,并将链接的 ArrayList 传递给 ChildRecyclerViewAdapter,然后将其全部划分以显示。

My goal is, as stated prior, to be able to search for items in the child recycler using the EditText that is in the HomeFragment.如前所述,我的目标是能够使用 HomeFragment 中的 EditText 搜索子回收器中的项目。 I've tried just getting the entirety of my database, and sorting through that with the name of the item, and then displaying that in the recyclerView, but I thought there might be a more elegant way.我试过只获取我的整个数据库,并使用项目名称对其进行排序,然后将其显示在 recyclerView 中,但我认为可能有更优雅的方法。

The only better way I can think is to maybe somehow just apply View.GONE to the Views whose names do not contain the string I get for searching.我能想到的唯一更好的方法是以某种方式将 View.GONE 应用于名称不包含我搜索的字符串的视图。 That would require the names of the child items, which I'm not sure how to get though.这将需要子项的名称,但我不确定如何获取。

The way I solved this is: Created a custom CardView class, that has a field for the name.我解决这个问题的方法是:创建一个自定义 CardView class,它有一个名称字段。

public class CustomCardView extends CardView {
    private String name;
    private String description;
    private String icon;
    public CustomCardView(@NonNull Context context) {
        super(context);
    }

    public CustomCardView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCardView, 0,0);
        try{
            name = a.getString(R.styleable.CustomCardView_appName);
            description = a.getString(R.styleable.CustomCardView_descriptionText);
        }finally {
            a.recycle();
        }
    }

    public CustomCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCardView, 0,0);
        try{
            name = a.getString(R.styleable.CustomCardView_appName);
            description = a.getString(R.styleable.CustomCardView_descriptionText);
        }finally {
            a.recycle();
        }
    }

    public String getName(){
        return name;
    }

    public String getDescription(){
        return description;
    }

    public void setName(String name){
        this.name = name;
        invalidate();
        requestLayout();
    }

    public void setDescription(String description){
        this.description = description;
        invalidate();
        requestLayout();
    }
}

Then, I created a static ArrayList, that would hold all the child objects.然后,我创建了一个 static ArrayList 来保存所有子对象。

public class RecyclerViewItemHolder {
    public static ArrayList<CustomCardView> childViews = new ArrayList<>();
    private static RecyclerViewItemHolder instance = null;
    private RecyclerViewItemHolder(){

    }
    public static RecyclerViewItemHolder getInstance(){
        if (instance == null){
            instance = new RecyclerViewItemHolder();
        }
        return instance;
    }
    public static ArrayList<CustomCardView> getChildViews(){
        return childViews;
    }
}

In the onBindViewHolder of the ChildRecyclerViewAdapter I added every CustomCardView to that ArrayList.在 ChildRecyclerViewAdapter 的 onBindViewHolder 中,我将每个 CustomCardView 添加到 ArrayList。

@Override
    public void onBindViewHolder(@NonNull ChildViewHolder holder, int position) {
RecyclerViewItemHolder.getInstance().childViews.add(holder.cardView);
}

Then, I accessed the ArrayList from the afterTextChanged method of the TextWatcher I set to the EditText.然后,我从设置为 EditText 的 TextWatcher 的 afterTextChanged 方法访问了 ArrayList。 I used a for loop to check if the name of the cardView contains the search query, and applied View.GONE if it didn't.我使用 for 循环检查 cardView 的名称是否包含搜索查询,如果不包含则应用 View.GONE。

private void initListeners() {
        binding.searchView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                for (CustomCardView cardView: RecyclerViewItemHolder.getChildViews()) {
                    if (!cardView.getName().contains(editable.toString())) {
                        cardView.setVisibility(View.GONE);
                    }else{
                        cardView.setVisibility(View.VISIBLE);
                    }
                }
            }
        });

The only issue left is that the empty categories don't disappear, and just stay there empty.剩下的唯一问题是空类别不会消失,只是空着留在那里。

Now, this is probably not the best way to do it, so I'll still appreciate any answers, or comments on how to improve on this solution.现在,这可能不是最好的方法,所以我仍然很感激任何答案,或关于如何改进这个解决方案的评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM