How to filter a RecyclerView with a SearchView

后端 未结 11 1715
孤独总比滥情好
孤独总比滥情好 2020-11-22 00:28

I am trying to implement the SearchView from the support library. I want the user to be to use the SearchView to filter a List of movi

11条回答
  •  长情又很酷
    2020-11-22 00:54

    I don't know why everyone is using 2 copies of the same list to solve this. This uses too much RAM...

    Why not just hide the elements that are not found, and simply store their index in a Set to be able to restore them later? That's much less RAM especially if your objects are quite large.

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter{
        private List myObjectsList; //holds the items of type MyObject
        private Set foundObjects; //holds the indices of the found items
    
        public MyRecyclerViewAdapter(Context context, List myObjectsList)
        {
            this.myObjectsList = myObjectsList;
            this.foundObjects = new HashSet<>();
            //first, add all indices to the indices set
            for(int i = 0; i < this.myObjectsList.size(); i++)
            {
                this.foundObjects.add(i);
            }
        }
    
        @NonNull
        @Override
        public SampleViewHolders onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View layoutView = LayoutInflater.from(parent.getContext()).inflate(
                    R.layout.my_layout_for_staggered_grid, null);
            MyRecyclerViewAdapter.SampleViewHolders rcv = new MyRecyclerViewAdapter.SampleViewHolders(layoutView);
            return rcv;
        }
    
        @Override
        public void onBindViewHolder(@NonNull SampleViewHolders holder, int position)
        {
            //look for object in O(1) in the indices set
            if(!foundObjects.contains(position))
            {
                //object not found => hide it.
                holder.hideLayout();
                return;
            }
            else
            {
                //object found => show it.
                holder.showLayout();
            }
    
            //holder.imgImageView.setImageResource(...)
            //holder.nameTextView.setText(...)
        }
    
        @Override
        public int getItemCount() {
            return myObjectsList.size();
        }
    
        public void findObject(String text)
        {
            //look for "text" in the objects list
            for(int i = 0; i < myObjectsList.size(); i++)
            {
                //if it's empty text, we want all objects, so just add it to the set.
                if(text.length() == 0)
                {
                    foundObjects.add(i);
                }
                else
                {
                    //otherwise check if it meets your search criteria and add it or remove it accordingly
                    if (myObjectsList.get(i).getName().toLowerCase().contains(text.toLowerCase()))
                    {
                        foundObjects.add(i);
                    }
                    else
                    {
                        foundObjects.remove(i);
                    }
                }
            }
            notifyDataSetChanged();
        }
    
        public class SampleViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener
        {
            public ImageView imgImageView;
            public TextView nameTextView;
    
            private final CardView layout;
            private final CardView.LayoutParams hiddenLayoutParams;
            private final CardView.LayoutParams shownLayoutParams;
    
            
            public SampleViewHolders(View itemView)
            {
                super(itemView);
                itemView.setOnClickListener(this);
                imgImageView = (ImageView) itemView.findViewById(R.id.some_image_view);
                nameTextView = (TextView) itemView.findViewById(R.id.display_name_textview);
    
                layout = itemView.findViewById(R.id.card_view); //card_view is the id of my androidx.cardview.widget.CardView in my xml layout
                //prepare hidden layout params with height = 0, and visible layout params for later - see hideLayout() and showLayout()
                hiddenLayoutParams = new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
                hiddenLayoutParams.height = 0;
                shownLayoutParams = new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
    
            @Override
            public void onClick(View view)
            {
                //implement...
            }
    
            private void hideLayout() {
                //hide the layout
                layout.setLayoutParams(hiddenLayoutParams);
            }
    
            private void showLayout() {
                //show the layout
                layout.setLayoutParams(shownLayoutParams);
            }
        }
    }
    

    And I simply have an EditText as my search box:

    cardsSearchTextView.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) {
                    myViewAdapter.findObject(editable.toString().toLowerCase());
                }
            });
    

    Result:

提交回复
热议问题