Search code examples
androidadaptersearchviewandroid-recyclerview

SearchView filter with RecyclerView


I have tried to implement a SearchView with suggestions (filter) in Fragment, but I have not managed it. I tried almost every tutorial but nothing worked for me. I would appreciate any help. Thank you

XML ...

    <!--appBar layout-->
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        android:fitsSystemWindows="true"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize">

        <!--searchView layout-->
        <android.support.v7.widget.SearchView
            android:id="@+id/search_view"
            app:layout_scrollFlags="scroll|enterAlways"
            android:iconifiedByDefault="false"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:closeIcon="@drawable/ic_clear_white_18dp"
            app:searchIcon="@drawable/ic_search_white_24dp"
            app:queryHint="@string/search_contact"
            app:iconifiedByDefault="false"
            android:background="@color/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

       </android.support.design.widget.AppBarLayout>

        <!-- recycler view-->
        <android.support.v7.widget.RecyclerView
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

Fragment

@Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_contact_list, container, false);

        searchView = (SearchView)view.findViewById(R.id.search_view);
        fabButton = (FloatingActionButton)view.findViewById(R.id.fab_button);

        //recycler view
        recyclerView = (RecyclerView)view.findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        contacts = SugarRecord.listAll(Contact.class);
        contactsAdapter = new ContactsAdapter(getActivity(), contacts);
        recyclerView.setAdapter(contactsAdapter);

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                // TODO: setFilter

                return true;
            }
        });

        return view;

Adapter

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactVH> {

    List<Contact> mContact;
    List<Contact> mContactFilter;

    Context mContext;

    public ContactsAdapter(Context context, List<Contact> contact) {
        this.mContact = contact;
        this.mContext = context;
    }

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

    @Override
    public void onBindViewHolder(ContactVH holder, int position) {
        holder.name.setText(mContact.get(position).getName());
    }

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

    class ContactVH extends RecyclerView.ViewHolder {
        @BindView(R.id.contact_name)
        TextView name;

        public ContactVH(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

    }

}

Solution

  • You can create class which extends Filter

    class YourFilterClass extends Filter {
    
    private List<Contact> contactList;
    private List<Contact> filteredContactList;
    private ContactsAdapter adapter;
    
        public YourFilterClass(List<Contact> contactList, ContactsAdapter adapter) {
         this.adapter = adapter;
         this.contactList = contactList;
         this.filteredContactList = new ArrayList();
        }
    
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
        filteredContactList.clear();
        final FilterResults results = new FilterResults();
    
        //here you need to add proper items do filteredContactList
         for (final Contact item : contactList) {
                if (item.getName().toLowerCase().trim().contains("pattern")) { 
                    filteredContactList.add(item);
                }
            }
    
            results.values = filteredContactList;
            results.count = filteredContactList.size();
            return results;
        }
    
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            adapter.setList(filteredContactList);
            adapter.notifyDataSetChanged();
        }
    

    }

    And then you can add this Filter to yours ContactsAdapter.

    public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactVH> {
    
    List<Contact> mContact;
    List<Contact> mContactFilter;
    YourFilterClass filter;
    
    Context mContext;
    
    public ContactsAdapter(Context context, List<Contact> contact) {
        this.mContact = contact;
        this.mContactFilter = contact;
        this.mContext = context;
        filter = new YourFilterClass(mContact, this);
    }
    
    @Override
    public ContactVH onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item_contact, parent, false);
        ContactVH viewHolder = new ContactVH(view);
        return viewHolder;
    }
    
    @Override
    public void onBindViewHolder(ContactVH holder, int position) {
        holder.name.setText(mContactFilter.get(position).getName());
    }
    // set adapter filtered list
    public void setList(List<Contact> list) {
        this.mContactFilter = list;
    }
    //call when you want to filter
    public void filterList(String text) {
        filter.filter(text);
    }
    
    @Override
    public int getItemCount() {
        return mContactFilter.size();
    }
    
    class ContactVH extends RecyclerView.ViewHolder {
        @BindView(R.id.contact_name)
        TextView name;
    
        public ContactVH(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    
    }
    

    }